diff --git a/.gitmodules b/.gitmodules index c11b15c65..775a704de 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,16 +19,12 @@ [submodule "modules/xscope_fileio"] path = modules/xscope_fileio/xscope_fileio url = git@github.com:xmos/xscope_fileio.git -[submodule "modules/inferencing/lib_nn"] - path = modules/inferencing/lib_nn - url = git@github.com:xmos/lib_nn.git [submodule "modules/lib_qspi_fast_read"] path = modules/lib_qspi_fast_read url = git@github.com:xmos/lib_qspi_fast_read.git -[submodule "modules/inferencing/lib_tflite_micro"] - path = modules/inferencing/lib_tflite_micro - url = git@github.com:xmos/lib_tflite_micro.git - ignore = dirty [submodule "modules/xua"] path = modules/xua url = git@github.com:xmos/lib_xua.git +[submodule "modules/sw_pll"] + path = modules/sw_pll + url = git@github.com:xmos/lib_sw_pll diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 374ffb12c..e23184728 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,34 @@ XCORE-VOICE change log ====================== +2.3.0 +----- + + * CHANGED: Updated Cyberon Wake Word engine. + * CHANGED: Updated XTC Tools to 15.3.0. + * CHANGED: Updated submodule fwk_io to version v3.6.0 from v3.3.0. + * CHANGED: Updated submodule fwk_core to version v1.1.0 from v1.0.2. + * CHANGED: Updated submodule fwk_voice to version v0.8.0 from v0.7.0. + * CHANGED: Updated submodule fwk_rtos to version 3.2.0 from 3.0.5. + * CHANGED: Updated submodule lib_src to version 2.7.0 from 2.4.0. + * CHANGED: Updated submodule xscope_fileio to version 1.2.0 from 1.1.2. + * ADDED: lib_sw_pll submodule v2.3.1. + * ADDED: xmos-ai-tools v1.3.1 Python requirement. + * REMOVED: Deleted inferencing submodule. + * ADDED: FFVA INT example with Cyberon speech recognition engine and model + (DSpotter v2.2.18.0). + * CHANGED: Moved files in folders device_memory, gpio_ctrl, intent_engine and + intent_handler from examples/ffd/src to folder modules/asr. + * CHANGED: Remove need to use external MCLK in FFVA INT examples + * ADDED: Support for DFU over I2C for FFVA INT example. + * ADDED: FFD example with I2S audio input to Cyberon speech recognition + engine and model. + * REMOVED: flash settings in .xn files, as they are not required by XMOS + Tools 15.3.0. + * ADDED: Support for reading registers over I2C slave in FFD examples. + * ADDED: Note in ASRC demo documentation about large latency in ASRC + processing. References to alternative application notes have been provided. + 2.2.0 ----- @@ -83,4 +111,3 @@ XCORE-VOICE change log ------ * ADDED: FFD demo using OLED display - diff --git a/Jenkinsfile b/Jenkinsfile index 056366b5b..455915bf3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,4 +1,4 @@ -@Library('xmos_jenkins_shared_library@v0.28.0') _ +@Library('xmos_jenkins_shared_library@v0.34.0') _ getApproval() @@ -15,20 +15,24 @@ pipeline { parameters { string( name: 'TOOLS_VERSION', - defaultValue: '15.2.1', + defaultValue: '15.3.0', description: 'The XTC tools version' ) + string( + name: 'XMOSDOC_VERSION', + defaultValue: 'v6.2.0', + description: 'The xmosdoc version' + ) booleanParam(name: 'NIGHTLY_TEST_ONLY', defaultValue: false, - description: 'Tests that only run during nightly builds.') - } + description: 'Tests that only run during nightly builds.' + ) + } // parameters environment { REPO = 'sln_voice' VIEW = getViewName(REPO) - PYTHON_VERSION = "3.8.11" VENV_DIRNAME = ".venv" BUILD_DIRNAME = "dist" - XMOSDOC_VERSION = 'v4.0' VRD_TEST_RIG_TARGET = "XCORE-AI-EXPLORER" PIPELINE_TEST_VECTORS = "pipeline_test_vectors" ASR_TEST_VECTORS = "asr_test_vectors" @@ -52,23 +56,20 @@ pipeline { } stage('Build tests') { steps { - script { - uid = sh(returnStdout: true, script: 'id -u').trim() - gid = sh(returnStdout: true, script: 'id -g').trim() - } - // pull docker images - sh "docker pull ghcr.io/xmos/xcore_builder:latest" - sh "docker pull ghcr.io/xmos/xcore_voice_tester:develop" - // host apps - sh "docker run --rm -u $uid:$gid -w /sln_voice -v $WORKSPACE:/sln_voice ghcr.io/xmos/xcore_builder:latest bash -l tools/ci/build_host_apps.sh" - // test firmware and filesystems - sh "docker run --rm -u $uid:$gid -w /sln_voice -v $WORKSPACE:/sln_voice ghcr.io/xmos/xcore_builder:latest bash -l tools/ci/build_tests.sh" - // List built files for log - sh "ls -la dist_host/" - sh "ls -la dist/" + createVenv(reqFile: "requirements.txt") + withTools(params.TOOLS_VERSION) { + withVenv { + // host apps + sh "tools/ci/build_host_apps.sh" + // test firmware and filesystems + sh "tools/ci/build_tests.sh" + // List built files for log + sh "ls -la dist_host/" + sh "ls -la dist/" + } // venv + } // tools } } - stage('ASRC Unit tests') { steps { withTools(params.TOOLS_VERSION) { @@ -98,14 +99,11 @@ pipeline { } } } - stage('Create virtual environment') { + stage('Install test requirements') { when { expression { params.NIGHTLY_TEST_ONLY == true } } steps { - // Create venv - sh "pyenv install -s $PYTHON_VERSION" - sh "~/.pyenv/versions/$PYTHON_VERSION/bin/python -m venv $VENV_DIRNAME" // Install dependencies withVenv() { sh "pip install git+https://github0.xmos.com/xmos-int/xtagctl.git" @@ -182,10 +180,8 @@ pipeline { withTools(params.TOOLS_VERSION) { withVenv { script { - uid = sh(returnStdout: true, script: 'id -u').trim() - gid = sh(returnStdout: true, script: 'id -g').trim() withXTAG(["$VRD_TEST_RIG_TARGET"]) { adapterIDs -> - sh "docker run --rm -u $uid:$gid --privileged -v /dev/bus/usb:/dev/bus/usb -w /sln_voice -v $WORKSPACE:/sln_voice ghcr.io/xmos/xcore_voice_tester:develop bash -l test/device_firmware_update/check_dfu.sh " + adapterIDs[0] + sh "test/device_firmware_update/check_dfu.sh " + adapterIDs[0] } sh "pytest test/device_firmware_update/test_dfu.py --readback_image test/device_firmware_update/test_output/readback_upgrade.bin --upgrade_image test/device_firmware_update/test_output/test_ffva_dfu_upgrade.bin" } @@ -220,6 +216,7 @@ pipeline { withTools(params.TOOLS_VERSION) { withVenv { script { + sh "xtagctl reset_all $VRD_TEST_RIG_TARGET" withXTAG(["$VRD_TEST_RIG_TARGET"]) { adapterIDs -> sh "test/pipeline/check_pipeline.sh $BUILD_DIRNAME/test_pipeline_ffva_adec_altarch.xe $PIPELINE_TEST_VECTORS test/pipeline/ffva_quick.txt test/pipeline/ffva_test_output $WORKSPACE/amazon_wwe " + adapterIDs[0] } @@ -236,6 +233,7 @@ pipeline { steps { withTools(params.TOOLS_VERSION) { withVenv { + sh "xtagctl reset_all $VRD_TEST_RIG_TARGET" script { withXTAG(["$VRD_TEST_RIG_TARGET"]) { adapterIDs -> sh "test/pipeline/check_pipeline.sh $BUILD_DIRNAME/test_pipeline_ffd.xe $PIPELINE_TEST_VECTORS test/pipeline/ffd_quick.txt test/pipeline/ffd_test_output $WORKSPACE/amazon_wwe " + adapterIDs[0] @@ -254,10 +252,13 @@ pipeline { withTools(params.TOOLS_VERSION) { withVenv { script { + sh "xtagctl reset_all $VRD_TEST_RIG_TARGET" withXTAG(["$VRD_TEST_RIG_TARGET"]) { adapterIDs -> - sh "test/asr/check_asr.sh Sensory $ASR_TEST_VECTORS test/asr/ffd_quick.txt test/asr/sensory_output " + adapterIDs[0] + sh "test/asr/check_asr.sh Sensory $ASR_TEST_VECTORS test/asr/ffd_quick_sensory.txt test/asr/sensory_output " + adapterIDs[0] + sh "test/asr/check_asr.sh Cyberon $ASR_TEST_VECTORS test/asr/ffd_quick_cyberon.txt test/asr/cyberon_output " + adapterIDs[0] } sh "pytest test/asr/test_asr.py --log test/asr/sensory_output/results.csv" + sh "pytest test/asr/test_asr.py --log test/asr/cyberon_output/results.csv" } } } @@ -273,28 +274,24 @@ pipeline { } } } - stage('Build docs') { - agent { label 'docker' } - stages { - stage ('Build docs with docker') { - steps { - checkout scm - sh 'git submodule update --init --recursive --depth 1 --jobs \$(nproc)' - sh "docker pull ghcr.io/xmos/xmosdoc:$XMOSDOC_VERSION" - sh """docker run -u "\$(id -u):\$(id -g)" \ - --rm \ - -v ${WORKSPACE}:/build \ - ghcr.io/xmos/xmosdoc:$XMOSDOC_VERSION -v""" - archiveArtifacts artifacts: 'doc/_build/**', allowEmptyArchive: true - } - } + stage('Build Documentation') { + agent { + label 'documentation&&docker' } + steps { + checkout scm + sh 'git submodule update --init --recursive --depth 1 --jobs \$(nproc)' + warnError("Docs") { + buildDocs(archiveZipOnly: true) + } // warnError("Docs") + } // steps post { cleanup { xcoreCleanSandbox() } } - } + } // stage('Build Documentation') + } } } diff --git a/README.rst b/README.rst index 0e40f4ba0..fe30ea47b 100644 --- a/README.rst +++ b/README.rst @@ -2,14 +2,14 @@ XCORE:registered:-VOICE Solution Repository ******************************************* -The XCORE-VOICE Solution consists of example designs and a C-based SDK for the development of audio front-end applications to support far-field voice use cases on the xcore.ai family of chips (XU316). The XCORE-VOICE design is currently based on FreeRTOS, leveraging the flexibility of the xcore.ai platform and providing designers with a familiar environment to customize and develop products. +The XCORE-VOICE Solution consists of example designs and a C-based SDK for the development of audio front-end applications to support far-field voice use cases on the xcore.ai family of chips (XU316). Most of the XCORE-VOICE designs are based on FreeRTOS, leveraging the flexibility of the xcore.ai platform and providing designers with a familiar environment to customize and develop products. The only exception is the Microphone Aggregation example which runs on bare-metal; this architecture was selected as it suits high IO bandwidth and low latency bridging type applications. XCORE-VOICE example designs provide turn-key solutions to enable easier product development for smart home applications such as light switches, thermostats, and home appliances. xcore.ai’s unique architecture providing powerful signal processing and accelerated AI capabilities combined with the XCORE-VOICE framework allows designers to incorporate keyword, event detection, or advanced local dictionary support to create a complete voice interface solution. -Cloning -******* +Obtaining the Source Code +************************* -Some dependent components are included as git submodules. These can be obtained by cloning this repository with the following command: +If you are interested in compiling and/or modifying the source code, you can download it from GitHub. As some dependent components are included as git submodules, the following command must be used for cloning this repository: :: @@ -27,17 +27,15 @@ Documentation See the READMEs for the early example applications: -`ASRC Demo `_ - -`FFD `_ + * `ASRC Demo `_: an example design for an asynchronous sampling rate converter (ASRC) -`FFVA `_ + * `FFD `_: two example designs for a far-field voice local control, each example contains a boot image and data partition binary -`Low Power FFD `_ + * `FFVA `_: two example designs for a far-field voice assistant, each example contains a boot image and data partition binary -`Microphone Aggregator `_ + * `Low Power FFD `_: an example design for a low-power far-field voice local control, the example contains a boot image and data partition binary -`Speech Recognition `_ + * `Microphone Aggregator `_: two example designs bridging 16 PDM microphones to either TDM16 slave or USB Audio Getting Help ************ diff --git a/doc/README.rst b/doc/README.rst deleted file mode 100644 index 1845dd266..000000000 --- a/doc/README.rst +++ /dev/null @@ -1,63 +0,0 @@ -#################### -Documentation Source -#################### - -This folder contains source files for the documentation and is intended for XMOS employees. Pre-built documentation is published on `the XMOS website`_. -The sources do not render well in GitHub or an RST viewer. In addition, some information is not visible at all and some links will not be functional. - -********************** -Building Documentation -********************** - -============= -Prerequisites -============= - -Use the `xmosdoc tool `_ either via docker or install it into a pip environment. - -======== -Building -======== - -To build the documentation, run the following command in the root of the repository: - -.. code-block:: console - - # via pip package - xmosdoc clean html latex - # via docker - $ docker run --rm -t -u "$(id -u):$(id -g)" -v $(pwd):/build ghcr.io/xmos/xmosdoc clean html latex - -HTML document output is saved in the ``doc/_build/html`` folder. Open ``index.html`` to preview the saved documentation. - -Please refer to the ``xmosdoc`` documentation for a complete guide on how to use the tool. - -********************** -Adding a New Component -********************** - -Follow the following steps to add a new component. - -- Add an entry for the new component's top-level document to the appropriate TOC in the documents tree. -- If the new component uses `Doxygen`, append the appropriate path(s) to the INPUT variable in `Doxyfile.inc`. -- If the new component includes `.rst` files that should **not** be part of the documentation build, append the appropriate pattern(s) to `exclude_patterns.inc`. - -*** -FAQ -*** - -Q: Is it possible to build just a subset of the documentation? - -A: Yes, however it is not recommended at this time. - -Q: Is it possible to used the ``livehtml`` feature of Sphinx? - -A: Yes, run xmosdoc with the ``--auto`` option. - -Q: Where can I learn more about the XMOS ``xmosdoc`` tools? - -A: See the https://github.com/xmos/xmosdoc repository. See the ``xmosdoc`` repository README for details on additional build options. - -Q: How do I suggest enhancements to the XMOS ``xmosdoc`` tool? - -A: Create a new issue here: https://github.com/xmos/xmosdoc/issues diff --git a/doc/programming_guide/asr/deploying/linux_macos.rst b/doc/programming_guide/asr/deploying/linux_macos.rst index 4cad2100d..99d7d0bbb 100644 --- a/doc/programming_guide/asr/deploying/linux_macos.rst +++ b/doc/programming_guide/asr/deploying/linux_macos.rst @@ -27,15 +27,16 @@ Run the following commands in the root folder to build the host application usin The host application, ``xscope_host_endpoint``, will be installed at ``/opt/xmos/bin``, and may be moved if desired. You may wish to add this directory to your ``PATH`` variable. -Before running the host application, you may need to add the location of ``xscope_endpoint.so`` to your ``LD_LIBRARY_PATH`` environment variable. This environment variable will be set if you run the host application in the XTC Tools command-line environment. For more information see `Configuring the command-line environment `__. +Before running the host application, you may need to add the location of ``xscope_endpoint.so`` to your ``LD_LIBRARY_PATH`` environment variable. This environment variable will be set if you run the host application in the XTC Tools command-line environment. For more information see `Configuring the command-line environment `__. Building the Firmware ===================== -Run the following commands in the root folder to build the firmware: +After having your python environment activated, run the following commands in the root folder to build the firmware: .. code-block:: console + pip install -r requirements.txt cmake -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build make example_asr @@ -64,7 +65,7 @@ From the build folder run: .. code-block:: console - xrun --xscope-realtime --xscope-port localhost:12345 example_asr.xe + xrun --xscope --xscope-port localhost:12345 example_asr.xe In a second console, run the following command in the ``examples/speech_recognition`` folder to run the host server: diff --git a/doc/programming_guide/asr/deploying/native_windows.rst b/doc/programming_guide/asr/deploying/native_windows.rst index 2f6085d3c..f49303c84 100644 --- a/doc/programming_guide/asr/deploying/native_windows.rst +++ b/doc/programming_guide/asr/deploying/native_windows.rst @@ -47,15 +47,16 @@ Then build the host application: The host application, ``xscope_host_endpoint.exe``, will install at ``\.xmos\bin``, and may be moved if desired. You may wish to add this directory to your ``PATH`` variable. -Before running the host application, you may need to add the location of ``xscope_endpoint.dll`` to your ``PATH``. This environment variable will be set if you run the host application in the XTC Tools command-line environment. For more information see `Configuring the command-line environment `__. +Before running the host application, you may need to add the location of ``xscope_endpoint.dll`` to your ``PATH``. This environment variable will be set if you run the host application in the XTC Tools command-line environment. For more information see `Configuring the command-line environment `__. Building the Firmware ===================== -Run the following commands in the root folder to build the firmware: +After having your python environment activated, run the following commands in the root folder to build the firmware: .. code-block:: console + pip install -r requirements.txt cmake -G Ninja -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build ninja example_asr @@ -86,7 +87,7 @@ From the build folder run: .. code-block:: console - xrun --xscope-realtime --xscope-port localhost:12345 example_asr.xe + xrun --xscope --xscope-port localhost:12345 example_asr.xe In a second console, run the following command in the ``examples/speech_recognition`` folder to run the host server: diff --git a/doc/programming_guide/asrc/overview.rst b/doc/programming_guide/asrc/overview.rst index f19248423..fa48b6415 100644 --- a/doc/programming_guide/asrc/overview.rst +++ b/doc/programming_guide/asrc/overview.rst @@ -2,11 +2,32 @@ Overview ******** +.. warning:: + + This example is based on the RTOS framework and drivers. This choice simplifies the example design, but it leads to high latency in the system. + The main sources of latency are: + + - Large block size used for ASRC processing: this is necessary to minimise latency associated with the intertile context and thread switching overhead. + - Large size of the buffer to which the ASRC output samples are written: a stable level (half full) must be reached before the start of streaming out over USB. + - RTOS task scheduling overhead between the tasks. + - bInterval of USB in the RTOS drivers is set to 4, i.e. one frame every 1 ms. + - Block based implementation of the USB and |I2S| RTOS drivers. + + The expected latencies for USB at 48 kHz are as follows: + + - USB -> ASRC -> |I2S|: from 8 ms at |I2S| at 192 kHz to 22 ms at 44.1 kHz + - |I2S| -> ASRC -> USB: from 13 ms at |I2S| at 192 kHz to 19 ms at 44.1 kHz + + For a proposed implementation with lower latency, please refer to the bare-metal examples below: + + - `AN02003: SPDIF/ADAT/I2S Slave Receive to I2S Slave Bridge with ASRC `__ + + This is the |SOFTWARE_URL| Asynchronous Sampling Rate Converter (ASRC) example design. The example system implements a stereo |I2S| Slave and a stereo Adaptive UAC2.0 interface and exchanges data between the two interfaces. Since the two interfaces are operating in different clock domains, there is an ASRC block between them that converts from the input to the output sampling rate. -There are two ASRC blocks, one each in the |I2S| → ASRC → USB and USB → ASRC → |I2S| path, as illustrated in the :ref:`fig-asrc-top-level-label`. +There are two ASRC blocks, one each in the |I2S| -> ASRC -> USB and USB -> ASRC -> |I2S| path, as illustrated in the :ref:`fig-asrc-top-level-label`. The diagram also shows the rate calculation path, which monitors and computes the instantaneous ratio between the ASRC input and output sampling rate. The rate ratio is used by the ASRC task to dynamically adapt filter coefficients using spline interpolation in its filtering stage. @@ -25,7 +46,7 @@ The |I2S| Slave interface is a stereo 32 bit interface supporting sampling rates The USB interface is a stereo, 32 bit, 48 kHz, High-Speed, USB Audio Class 2, Adaptive interface. The ASRC algorithm implemented in the `lib_src `_ library is used for the ASRC processing. -The ASRC processing is block based and works on a block size of 244 samples per channel in the |I2S| → ASRC → USB path and 96 samples per channel in the USB → ASRC → |I2S| path. +The ASRC processing is block based and works on a block size of 244 samples per channel in the |I2S| -> ASRC -> USB path and 96 samples per channel in the USB -> ASRC -> |I2S| path. Supported Hardware ================== @@ -39,7 +60,7 @@ The table :ref:`table-pin-connections-label` lists the pins on the XK-VOICE-L71 .. _table-pin-connections-label: .. list-table:: XK-VOICE-L71 RPI host interface header (J4) connections - :widths: 30 50 + :widths: 50 50 :header-rows: 1 :align: left @@ -56,8 +77,6 @@ The table :ref:`table-pin-connections-label` lists the pins on the XK-VOICE-L71 * - One of the GND pins (6, 14, 20, 30, 34, 9, 25 or 39) - GND on the |I2S| Master board - - Obtaining the app files ======================= @@ -72,7 +91,7 @@ Download the main repo and submodules using: Building the app ================ -First install and source the XTC version: 15.2.1 tools. The output should be +First install and source the XTC version: |TOOLS_VERSION| tools. For example with version 15.2.1, the output should be something like this: :: @@ -86,11 +105,12 @@ something like this: Linux or Mac ------------ -To build for the first time, run ``cmake`` to create the +To build for the first time, activate your python environment, run ``cmake`` to create the make files: :: + $ pip install -r requirements.txt $ mkdir build $ cd build $ cmake --toolchain ../xmos_cmake_toolchain/xs3a.cmake .. @@ -107,10 +127,9 @@ Following initial ``cmake`` build, for subsequent builds, as long as new source Windows ------- -It is highly recommended to use ``Ninja`` as the make system under -``cmake``. Not only is it a lot faster than MSVC ``nmake``, it also -works around an issue where certain path names may cause an issue with -the XMOS compiler under Windows. +It is recommended to use `Ninja` or `xmake` as the make system under Windows. +`Ninja` has been observed to be faster than `xmake`, however `xmake` comes natively with XTC tools. +This firmware has been tested with `Ninja` version v1.11.1. To install Ninja, follow these steps: @@ -122,11 +141,12 @@ To install Ninja, follow these steps: set the path in the current command line session using something like ``set PATH=%PATH%;C:\Users\xmos\utils\ninja`` -To build for the first time, run ``cmake`` to create the +To build for the first time, activate your python environment, run ``cmake`` to create the make files: :: + $ pip install -r requirements.txt $ md build $ cd build $ cmake -G "Ninja" --toolchain ..\xmos_cmake_toolchain\xs3a.cmake .. diff --git a/doc/programming_guide/asrc/resource_usage.rst b/doc/programming_guide/asrc/resource_usage.rst index d628828d7..360c2c16e 100644 --- a/doc/programming_guide/asrc/resource_usage.rst +++ b/doc/programming_guide/asrc/resource_usage.rst @@ -68,8 +68,8 @@ Intertile contexts The application uses 3 intertile contexts for cross tile communication. - * A dedicated intertile context for sending ASRC output data from the I2S tile to the USB tile. - * A dedicated intertile context for sending ASRC output data from the USB tile to the I2S tile. + * A dedicated intertile context for sending ASRC output data from the |I2S| tile to the USB tile. + * A dedicated intertile context for sending ASRC output data from the USB tile to the |I2S| tile. * The intertile context for all other cross tile communication. diff --git a/doc/programming_guide/asrc/software_architecture.rst b/doc/programming_guide/asrc/software_architecture.rst index 2336c6fb8..f3ab04fe9 100644 --- a/doc/programming_guide/asrc/software_architecture.rst +++ b/doc/programming_guide/asrc/software_architecture.rst @@ -27,7 +27,7 @@ The :ref:`fig-ASRC-task-diagram-label` shows the RTOS tasks and other components The tasks can roughly be categorised as belonging to the USB driver, |I2S| driver or the application code categories. -The actual ASRC processing happens in four tasks across the two tiles; the **usb_audio_out_asrc task**, **i2s_audio_recv_asrc** task, and two instances of **asrc_one_channel_task**, one on each tile. +The actual ASRC processing happens in four tasks across the two tiles; the **usb_audio_out_asrc task**, **i2s_audio_recv_asrc task**, and two instances of **asrc_one_channel task**, one on each tile. This is described in more detail in the :ref:`application-components-label` section below. Most of the tasks are involved in the ASRC processing data path, while a few are involved in monitoring the input and output data rates @@ -53,9 +53,9 @@ It interfaces with the USB app level thread (**usb_task**) via shared memory and **usb_task** implements the app level USB driver functionality. The app level USB driver is based on `TinyUSB `_ which hooks into the application by means of callback functions. The **usb_isr** task is triggered by the interrupt and parses the data transferred from XUD and places it on a queue that the **usb_task** blocks on for further processing. -For example, on completion of an EP1 OUT transfer, the transfer completion gets notified on the **usb_xud_thread → usb_isr → usb_task** path, +For example, on completion of an EP1 OUT transfer, the transfer completion gets notified on the **usb_xud_thread -> usb_isr -> usb_task** path, and the **usb_task** calls the ``tud_audio_rx_done_post_read_cb()`` function to have the application process the data received from the host. -On completion of an EP1 IN transfer, the transfer completion again follows the **usb_xud_thread → usb_isr → usb_task** path, and **usb_task** calls the ``tud_audio_tx_done_pre_load_cb()`` +On completion of an EP1 IN transfer, the transfer completion again follows the **usb_xud_thread -> usb_isr -> usb_task** path, and **usb_task** calls the ``tud_audio_tx_done_pre_load_cb()`` callback function to have the application load the EP1 IN data for the next transfer. **samples_to_host_stream_buf** and **samples_from_host_stream_buf** are circular buffers shared between the application and the USB driver and allow for decoupling one from the other. @@ -111,34 +111,34 @@ It has other rate-monitoring related responsibilities that are described in the **i2s_to_usb_intertile** task receives the ASRC output data generated by **i2s_audio_recv_asrc** over the inter-tile context onto the USB tile and writes it to the USB ``samples_to_host_stream_buf``. It has other rate-monitoring related responsibilities that are described in the :ref:`rate-server-label` section. -The :ref:`asrc_i2s_to_usb_data_path-label` diagram shows the application tasks involved in the |I2S| → ASRC → USB path processing and their interaction with each other. +The :ref:`asrc_i2s_to_usb_data_path-label` diagram shows the application tasks involved in the |I2S| -> ASRC -> USB path processing and their interaction with each other. .. _asrc_i2s_to_usb_data_path-label: .. figure:: diagrams/asrc_i2s_to_usb_data_path.png :align: center :width: 100% - :alt: ASRC |I2S| → ASRC → USB data path + :alt: ASRC |I2S| -> ASRC -> USB data path - |I2S| → ASRC → USB data path + |I2S| -> ASRC -> USB data path -The :ref:`asrc_usb_to_i2s_data_path-label` diagram shows the application tasks involved in the USB → ASRC → |I2S| path processing and their interaction with each other. +The :ref:`asrc_usb_to_i2s_data_path-label` diagram shows the application tasks involved in the USB -> ASRC -> |I2S| path processing and their interaction with each other. .. _asrc_usb_to_i2s_data_path-label: .. figure:: diagrams/asrc_usb_to_i2s_data_path.png :align: center :width: 100% - :alt: USB → ASRC → |I2S| data path + :alt: USB -> ASRC -> |I2S| data path - USB → ASRC → |I2S| data path + USB -> ASRC -> |I2S| data path .. _rate-server-label: **rate_server** --------------- -The ASRC ``process_frame`` API requires the caller to calculate and send the instantaneous ratio between the ASRC input and output rate. The **rate_server** is responsible for calculating these rate ratios for both USB → ASRC → |I2S| and |I2S| → ASRC → USB directions. +The ASRC ``process_frame`` API requires the caller to calculate and send the instantaneous ratio between the ASRC input and output rate. The **rate_server** is responsible for calculating these rate ratios for both USB -> ASRC -> |I2S| and |I2S| -> ASRC -> USB directions. Additionally, the application also monitors the average buffer fill levels of the buffers holding ASRC output to prevent any overflows or underflows of the respective buffer. A gradual drift in the buffer fill level indicates that the rate ratio is being under or over calculated by the **rate_server**. This could happen either due to jitter in the actual rates or precision limitations when calculating the rates. @@ -179,8 +179,8 @@ either calculating it or getting it through shared memory from other USB tasks o The |I2S| related information (1 and 4 above) is calculated in the **rate_server** itself with information available for calculating these available through shared memory from other tasks on this tile. -After calculating the rates, the **rate_server** sends the rate ratio for the USB → ASRC → |I2S| side to the **usb_to_i2s_intertile** task over the inter-tile context and it is made available to the -**usb_audio_out_asrc** task through shared memory. The |I2S| → ASRC → USB side rate ratio is also made available to the **i2s_audio_recv_asrc** task through shared memory since it runs on the same tile as the rate server. +After calculating the rates, the **rate_server** sends the rate ratio for the USB -> ASRC -> |I2S| side to the **usb_to_i2s_intertile** task over the inter-tile context and it is made available to the +**usb_audio_out_asrc** task through shared memory. The |I2S| -> ASRC -> USB side rate ratio is also made available to the **i2s_audio_recv_asrc** task through shared memory since it runs on the same tile as the rate server. The :ref:`fig-rate-server-label` diagram shows the code flow during the rate ratio calculation process, focussing on the **usb_to_intertile** task that triggers the **rate_server** and the **rate_server** task where the rate ratios are calculated. @@ -211,7 +211,7 @@ Handling USB speaker interface close -> open events =================================================== When the USB host stops streaming to the device and then starts again, this event is detected through calls to the ``tud_audio_set_itf_close_EP_cb`` and ``tud_audio_set_itf_cb`` functions. -The ASRC output buffer in the USB → ASRC → |I2S| path (|I2S| ``send_buffer``) is reset. +The ASRC output buffer in the USB -> ASRC -> |I2S| path (|I2S| ``send_buffer``) is reset. Zeroes are then sent over |I2S| until the buffer fills to a stable level, when we resume streaming out of this buffer to send samples over |I2S|. The average buffer calculation state for the |I2S| ``send_buffer`` is also reset and a new stable average is calculated against which the average buffer levels are corrected. @@ -219,6 +219,6 @@ Handling USB mic interface close -> open events =============================================== If the USB host stops streaming from the device and then starts again, this event is detected through calls to the ``tud_audio_set_itf_close_EP_cb`` and ``tud_audio_set_itf_cb`` functions. -The ASRC output buffer in the |I2S| → ASRC → USB is reset (USB ``samples_to_host_stream_buf``). +The ASRC output buffer in the |I2S| -> ASRC -> USB is reset (USB ``samples_to_host_stream_buf``). Zeroes are streamed to the host until the buffer fills to a stable level, when we resume streaming out of this buffer to send samples over USB. The average buffer calculation state for the USB ``samples_to_host_stream_buf`` is also reset and a new stable average is calculated against which the average buffer levels are corrected. diff --git a/doc/programming_guide/example_designs.rst b/doc/programming_guide/example_designs.rst index b7a7c66bc..c33fb9b25 100644 --- a/doc/programming_guide/example_designs.rst +++ b/doc/programming_guide/example_designs.rst @@ -9,6 +9,5 @@ Example Designs ffd/ffd low_power_ffd/low_power_ffd ffva/ffva - asr/asr mic_aggregator/mic_aggregator asrc/asrc diff --git a/doc/programming_guide/ffd/deploying/configuration.rst b/doc/programming_guide/ffd/deploying/configuration.rst index 905994cd5..720b399ca 100644 --- a/doc/programming_guide/ffd/deploying/configuration.rst +++ b/doc/programming_guide/ffd/deploying/configuration.rst @@ -4,12 +4,13 @@ Configuring the Firmware ======================== -The default application performs as described in the :ref:`sln_voice_ffd_overview`. There are numerous compile time options that can be added to change the example design without requiring code changes. To change the options explained in the table below, add the desired configuration variables to the APP_COMPILE_DEFINITIONS cmake variable located `here `_. +The default application performs as described in the :ref:`sln_voice_ffd_overview`. There are numerous compile time options that can be added to change the example design without requiring code changes. To change the options explained in the table below, add the desired configuration variables to the APP_COMPILE_DEFINITIONS cmake variable in the ``.cmake`` file located in the ``examples/ffd/`` folder. If options are changed, the application firmware must be rebuilt. .. list-table:: FFD Compile Options - :widths: 90 85 20 + :class: longtable + :widths: 48 42 10 :header-rows: 1 :align: left @@ -31,15 +32,42 @@ If options are changed, the application firmware must be rebuilt. * - appconfINTENT_UART_OUTPUT_ENABLED - Enables/disables the UART intent message - 1 - * - appconfINTENT_I2C_OUTPUT_ENABLED - - Enables/disables the |I2C| intent message + * - appconfINTENT_UART_DEBUG_INFO_ENABLED + - Enables/disables the UART intent debug information + - 0 + * - appconfI2C_MASTER_DAC_ENABLED + - Enables/disables configuring the DAC over |I2C| master + - 1 + * - appconfINTENT_I2C_MASTER_OUTPUT_ENABLED + - Enables/disables sending the intent message over |I2C| master - 1 + * - appconfINTENT_I2C_MASTER_DEVICE_ADDR + - Sets the address of the |I2C| device receiving the intent via the |I2C| master interface + - 0x01 + * - appconfINTENT_I2C_SLAVE_POLLED_ENABLED + - Enables/disables allowing another device to poll the intent message via |I2C| slave + - 0 + * - appconfI2C_SLAVE_DEVICE_ADDR + - Sets the address of the |I2C| device receiving the intent via the |I2C| slave interface + - 0x42 + * - appconfINTENT_I2C_REG_ADDRESS + - Sets the address of the |I2C| register to store the intent message, this value can be read via the |I2C| slave interface + - 0x01 * - appconfUART_BAUD_RATE - Sets the baud rate for the UART tx intent interface - 9600 - * - appconfINTENT_I2C_OUTPUT_DEVICE_ADDR - - Sets the |I2C| slave address to transmit the intent to - - 0x01 + * - appconfUSE_I2S_INPUT + - Replace |I2S| audio source instead of the microphone array audio source. + - 0 + * - appconfI2S_MODE + - Select |I2S| mode, supported values are appconfI2S_MODE_MASTER and appconfI2S_MODE_SLAVE + - master + * - appconfI2S_AUDIO_SAMPLE_RATE + - Select the sample rate of the |I2S| interface, supported values are 16000 and 48000 + - 16000 + * - appconfRECOVER_MCLK_I2S_APP_PLL + - Enables/disables the recovery of the MCLK from the Software PLL application; this removes the need to use an external MCLK. + - 0 * - appconfINTENT_TRANSPORT_DELAY_MS - Sets the delay between host wake up requested and |I2C| and UART keyword code transmission - 50 @@ -58,3 +86,47 @@ If options are changed, the application firmware must be rebuilt. * - appconfAUDIO_PIPELINE_SKIP_AGC - Enables/disables the AGC - 0 + +.. note:: + + The ``example_ffd_i2s_input_cyberon`` has different default values from the ones in the table above. + The list of updated values can be found in the ``APP_COMPILE_DEFINITIONS`` list in ``examples\ffd\ffd_i2s_input_cyberon.cmake``. + +Configuring the |I2C| interfaces +-------------------------------- + +The |I2C| interfaces are used to configure the DAC and to communicate with the host. The |I2C| interface can be configured as a master or a slave. +The DAC must be configured at bootup via the |I2C| master interface. +The |I2C| master is used when the FFD example asynchronously sends intent messages to the host. The |I2C| slave is used when the host wants to read intent messages from the FFD example through polling. + +.. note:: + The |I2C| interface cannot operate as both master and slave simultaneously. The FFD example design uses the |I2C| master interface to configure the DAC at device initialisation. + However, if the host reads intent messages from the FFD example using the |I2C| slave interface, the |I2C| master interface will be disabled after the DAC configuration is complete. + +To send the intent ID via the |I2C| master interface when a command is detected, set the following variables: + + - ``appconfINTENT_I2C_MASTER_OUTPUT_ENABLED`` to 1. + - ``appconfINTENT_I2C_MASTER_DEVICE_ADDR`` to the desired address used by the |I2C| slave device. + - ``appconfINTENT_I2C_SLAVE_POLLED_ENABLED`` to 0, this will disable the |I2C| slave interface. + +To configure the FFD example so that the host can poll for the intent via the |I2C| slave interface, set the following variables: + + - ``appconfINTENT_I2C_SLAVE_POLLED_ENABLED`` to 1. + - ``appconfI2C_SLAVE_DEVICE_ADDR`` to the desired address used by the |I2C| master device. + - ``appconfINTENT_I2C_REG_ADDRESS`` to the desired register read by the |I2C| master device. + - ``appconfINTENT_I2C_MASTER_OUTPUT_ENABLED`` to 0, this will disable the |I2C| master interface after initialization. + +The handling of the |I2C| slave registers is done in the ``examples\ffd\src\i2c_reg_handling.c`` file. The variable ``appconfINTENT_I2C_REG_ADDRESS`` is used in the callback function ``read_device_reg()``. + +Configuring the |I2S| interface +------------------------------- + +The |I2S| interface is used to play the audio command response to the DAC, and/or to receive the audio samples from the host. The |I2S| interface can be configured as either a master or a slave. +To configure the |I2S| interface, set the following variables: + + - ``appconfI2S_ENABLED`` to 1. + - ``appconfI2S_MODE`` to the desired mode, either ``appconfI2S_MODE_MASTER`` or ``appconfI2S_MODE_SLAVE``. + - ``appconfI2S_AUDIO_SAMPLE_RATE`` to the desired sample rate, either 16000 or 48000. + - ``appconfRECOVER_MCLK_I2S_APP_PLL`` to 1 if an external MCLK is not available, otherwise set it to 0. + - ``appconfAUDIO_PLAYBACK_ENABLED`` to 1, if the intent audio is to be played back. + - ``appconfUSE_I2S_INPUT`` to 1, if the |I2S| audio source is to be used instead of the microphone array audio source. diff --git a/doc/programming_guide/ffd/deploying/linux_macos.rst b/doc/programming_guide/ffd/deploying/linux_macos.rst index 04eee990f..43bdee5cb 100644 --- a/doc/programming_guide/ffd/deploying/linux_macos.rst +++ b/doc/programming_guide/ffd/deploying/linux_macos.rst @@ -11,6 +11,11 @@ This document explains how to deploy the software using *CMake* and *Make*. In the commands below ```` can be either ``sensory`` or ``cyberon``, depending on the choice of the speech recognition engine and model. +.. note:: + + The Cyberon speech recognition engine is integrated in two examples. The ``example_ffd_cyberon`` use the microphone array as the audio source, and the ``example_ffd_i2s_input_cyberon`` uses the |I2S| interface as the audio source. + In the rest of this section, we use only the ``example_ffd_`` as an example. + Building the Host Applications ============================== @@ -31,10 +36,11 @@ The host applications will be installed at ``/opt/xmos/bin``, and may be moved i Building the Firmware ===================== -Run the following commands in the root folder to build the firmware: +After having your python environment activated, run the following commands in the root folder to build the firmware: .. code-block:: console + pip install -r requirements.txt cmake -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build make example_ffd_ diff --git a/doc/programming_guide/ffd/deploying/native_windows.rst b/doc/programming_guide/ffd/deploying/native_windows.rst index bed339b56..ce5cdc381 100644 --- a/doc/programming_guide/ffd/deploying/native_windows.rst +++ b/doc/programming_guide/ffd/deploying/native_windows.rst @@ -17,6 +17,14 @@ install with ``winget`` by running the following commands in *PowerShell*: # Reload user Path $env:Path=[System.Environment]::GetEnvironmentVariable("Path","User") +.. note:: + In the commands below ```` can be either ``sensory`` or ``cyberon``, depending on the choice of the speech recognition engine and model. + +.. note:: + + The Cyberon speech recognition engine is integrated in two examples. The ``example_ffd_cyberon`` use the microphone array as the audio source, and the ``example_ffd_i2s_input_cyberon`` uses the |I2S| interface as the audio source. + In the rest of this section, we use only the ``example_ffd_`` as an example. + Building the Host Applications ============================== @@ -49,10 +57,11 @@ The host applications will be installed at ``%USERPROFILE%\.xmos\bin``, and may Building the Firmware ===================== -Run the following commands in the root folder to build the firmware: +After having your python environment activated, run the following commands in the root folder to build the firmware: .. code-block:: console + pip install -r requirements.txt cmake -G Ninja -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build ninja example_ffd_ diff --git a/doc/programming_guide/ffd/overview.rst b/doc/programming_guide/ffd/overview.rst index d5a5b279e..7e5cf1dcc 100644 --- a/doc/programming_guide/ffd/overview.rst +++ b/doc/programming_guide/ffd/overview.rst @@ -5,7 +5,20 @@ Overview ******** -This is the far-field voice local command (FFD) example design. Two examples are provided: both examples include speech recognition and a local dictionary. One example uses the Sensory TrulyHandsfree™ (THF) libraries, and the other one uses the Cyberon DSPotter™ libraries. +This is the far-field voice local command (FFD) example design. Three examples are provided: all examples include speech recognition and a local dictionary. One example uses the Sensory TrulyHandsfree™ (THF) libraries, and the other ones use the Cyberon DSPotter™ libraries. The two examples with the Cyberon DSPotter™ libraries differ in the audio source fed into the intent engine. One example uses the audio source from the microphone array, and the other uses the audio source from the |I2S| interface. + +The examples using the microphone array as the audio source include an audio pipeline with the following stages: + + #. Interference Canceler (IC) + Voice To Noise Ratio Estimator (VNR) + #. Noise Suppressor (NS) + #. Adaptive Gain Control (AGC) + +The FFD examples provide several options to inform the host of a possible intent detected by the intent engine. The device can notify the host by: + + - sending the intent ID over a UART interface upon detecting the intent + - sending the intent ID over an |I2C| master interface upon detecting the intent + - allowing the host to poll the last detected intent ID over the |I2C| slave interface + - listening to an audio message over an |I2S| interface When a wakeword phrase is detected followed by a command phrase, the application will output an audio response and a discrete message over |I2C| and UART. diff --git a/doc/programming_guide/ffd/software_desc/bsp_config.rst b/doc/programming_guide/ffd/software_desc/bsp_config.rst index 4b9df673c..ae0518113 100644 --- a/doc/programming_guide/ffd/software_desc/bsp_config.rst +++ b/doc/programming_guide/ffd/software_desc/bsp_config.rst @@ -1,8 +1,8 @@ .. _sln_voice_ffd_bsp_config: -########## -bsp_config -########## +####################### +examples/ffd/bsp_config +####################### This folder contains bsp_configs for the FFD application. More information on bsp_configs can be found in the RTOS Framework documentation. diff --git a/doc/programming_guide/ffd/software_desc/ext.rst b/doc/programming_guide/ffd/software_desc/ext.rst deleted file mode 100644 index adb0a4947..000000000 --- a/doc/programming_guide/ffd/software_desc/ext.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. _sln_voice_ffd_ext: - -### -ext -### - -This folder contains FFD application debug and experimental extensions. - -.. list-table:: FFD ext - :widths: 30 50 - :header-rows: 1 - :align: left - - * - Filename/Directory - - Description - * - src directory - - custom code for USB output and debug - * - ffd_dev.cmake - - cmake for declaring FFD experimental configs - * - ffd_ext.cmake - - cmake for declaring FFD extensions - * - ffd_usb_audio_testing.cmake - - cmake for declaring FFD usb debug extension diff --git a/doc/programming_guide/ffd/software_desc/filesystem_support.rst b/doc/programming_guide/ffd/software_desc/filesystem_support.rst index f4e842d9e..1633c19f9 100644 --- a/doc/programming_guide/ffd/software_desc/filesystem_support.rst +++ b/doc/programming_guide/ffd/software_desc/filesystem_support.rst @@ -1,8 +1,8 @@ .. _sln_voice_ffd_filesystem_support: -################## -filesystem_support -################## +############################### +examples/ffd/filesystem_support +############################### This folder contains filesystem contents for the FFD application. diff --git a/doc/programming_guide/ffd/software_desc/intent_engine.rst b/doc/programming_guide/ffd/software_desc/intent_engine.rst index 3331173ad..49f81760c 100644 --- a/doc/programming_guide/ffd/software_desc/intent_engine.rst +++ b/doc/programming_guide/ffd/software_desc/intent_engine.rst @@ -1,12 +1,12 @@ -.. _sln_voice_ffd_intent_engine: +.. _sln_voice_intent_engine: -################# -src/intent_engine -################# +######################### +modules/asr/intent_engine +######################### -This folder contains the intent engine module for the FFD application. +This folder contains the intent engine module for the FFD and FFVA applications. -.. list-table:: FFD Intent Engine +.. list-table:: ASR Intent Engine :widths: 30 50 :header-rows: 1 :align: left @@ -43,12 +43,12 @@ intent_engine_create This function has the role of creating the model running task and providing a pointer, which can be used by the application to handle the output intent result. In the case of the default configuration, the application provides a FreeRTOS Queue object. -In FFD, the audio pipeline output is on tile 1 and the ASR engine on tile 0. +The ASR engine is on tile 0 in both FFD and FFVA, but the audio pipeline output is on tile 1 for FFD and on tile 0 for FFVA. .. code-block:: c :caption: intent_engine_create snippet (intent_engine_io.c) - #if ASR_TILE_NO == AUDIO_PIPELINE_TILE_NO + #if ASR_TILE_NO == AUDIO_PIPELINE_OUTPUT_TILE_NO intent_engine_task_create(priority); #else intent_engine_intertile_task_create(priority); @@ -67,7 +67,7 @@ samples at startup. :caption: intent_engine_create snippet (intent_engine_io.c) int sync = 0; - #if ON_TILE(AUDIO_PIPELINE_TILE_NO) + #if ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) size_t len = rtos_intertile_rx_len(intertile_ctx, appconfINTENT_ENGINE_READY_SYNC_PORT, RTOS_OSAL_WAIT_FOREVER); xassert(len == sizeof(sync)); rtos_intertile_rx_data(intertile_ctx, &sync, sizeof(sync)); @@ -80,13 +80,13 @@ intent_engine_sample_push This function has the role of sending the ASR output channel from the audio pipeline to the intent engine. -In FFD, the audio pipeline output is on tile 1 and the ASR engine on tile 0. +The ASR engine is on tile 0 in both FFD and FFVA, but the audio pipeline output is on tile 1 for FFD and on tile 0 for FFVA. .. code-block:: c :caption: intent_engine_create snippet (intent_engine_io.c) - #if appconfINTENT_ENABLED && ON_TILE(AUDIO_PIPELINE_TILE_NO) - #if ASR_TILE_NO == AUDIO_PIPELINE_TILE_NO + #if appconfINTENT_ENABLED && ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) + #if ASR_TILE_NO == AUDIO_PIPELINE_OUTPUT_TILE_NO intent_engine_samples_send_local( frames, buf); diff --git a/doc/programming_guide/ffd/software_desc/intent_handler.rst b/doc/programming_guide/ffd/software_desc/intent_handler.rst index a5a8704d5..4a2d5e028 100644 --- a/doc/programming_guide/ffd/software_desc/intent_handler.rst +++ b/doc/programming_guide/ffd/software_desc/intent_handler.rst @@ -1,12 +1,12 @@ -.. _sln_voice_ffd_intent_handler: +.. _sln_voice_intent_handler: -################## -src/intent_handler -################## +########################## +modules/asr/intent_handler +########################## -This folder contains ASR output handling modules for the FFD application. +This folder contains ASR output handling modules for the FFD and FFVA applications. -.. list-table:: FFD Intent handler +.. list-table:: ASR Intent handler :widths: 30 50 :header-rows: 1 :align: left diff --git a/doc/programming_guide/ffd/software_desc/overview.rst b/doc/programming_guide/ffd/software_desc/overview.rst index 1eb153e93..fd291887b 100644 --- a/doc/programming_guide/ffd/software_desc/overview.rst +++ b/doc/programming_guide/ffd/software_desc/overview.rst @@ -83,7 +83,7 @@ The estimated power usage of the example application varies from 100-141 mW. Thi - 37.260 Note that these are typical usage statistics for a representative run of the application on hardware. Core allocations may shift run-to-run in a scheduled RTOS. -These statistics are generated by slicing the representative run into 10 ms chunks and calculating % time per chunk not spent in the FreeRTOS IDLE tasks. +These statistics are generated by slicing the representative run into 10 ms chunks and calculating % time per chunk not spent in the FreeRTOS IDLE tasks. Therefore, the underlying distribution of these 10 ms bins should not be assumed to be Normal; this has implications on e.g. the interpretation of the Standard Deviation given here. .. list-table:: FFD Power Usage @@ -99,7 +99,7 @@ Therefore, the underlying distribution of these 10 ms bins should not be assumed The description of the software is split up by folder: .. list-table:: FFD Software Description - :widths: 40 120 + :widths: 40 60 :header-rows: 1 :align: left @@ -107,13 +107,11 @@ The description of the software is split up by folder: - Description * - :ref:`sln_voice_ffd_bsp_config` - Board support configuration setting up software based IO peripherals - * - :ref:`sln_voice_ffd_ext` - - Application extensions * - :ref:`sln_voice_ffd_filesystem_support` - Filesystem contents for application * - :ref:`sln_voice_ffd_src` - Main application - * - :ref:`sln_voice_ffd_intent_engine` + * - :ref:`sln_voice_intent_engine` - Intent engine integration - * - :ref:`sln_voice_ffd_intent_handler` + * - :ref:`sln_voice_intent_handler` - Intent engine output integration diff --git a/doc/programming_guide/ffd/software_desc/src.rst b/doc/programming_guide/ffd/software_desc/src.rst index 2d887ba39..08dbd9d63 100644 --- a/doc/programming_guide/ffd/software_desc/src.rst +++ b/doc/programming_guide/ffd/software_desc/src.rst @@ -1,8 +1,8 @@ .. _sln_voice_ffd_src: -### -src -### +################ +examples/ffd/src +################ This folder contains the core application source. diff --git a/doc/programming_guide/ffd/software_description.rst b/doc/programming_guide/ffd/software_description.rst index bf3ae4ca7..4000d418a 100644 --- a/doc/programming_guide/ffd/software_description.rst +++ b/doc/programming_guide/ffd/software_description.rst @@ -9,9 +9,7 @@ Software Description :maxdepth: 1 software_desc/overview - ../asr/asr software_desc/bsp_config - software_desc/ext software_desc/filesystem_support software_desc/src software_desc/intent_engine diff --git a/doc/programming_guide/ffd/speech_recognition_cyberon.rst b/doc/programming_guide/ffd/speech_recognition_cyberon.rst index 7f01b92a7..f1bf64da4 100644 --- a/doc/programming_guide/ffd/speech_recognition_cyberon.rst +++ b/doc/programming_guide/ffd/speech_recognition_cyberon.rst @@ -1,6 +1,3 @@ -.. include:: -.. include:: ../../substitutions.rst - .. _sln_voice_ffd_speech_recognition_cyberon: ############################ @@ -22,7 +19,8 @@ The Cyberon DSpotter™ speech recognition engine runs proprietary models to ide One model for US English is provided. For any technical questions or additional models please contact Cyberon. -To replace the Cyberon engine with a different engine, refer to the ASR documentation on :ref:`sln_voice_asr_programming_guide` +.. TODO: Check if the line below can be removed or re-added +.. To replace the Cyberon engine with a different engine, refer to the ASR documentation on :ref:`sln_voice_asr_programming_guide` Dictionary command table ======================== diff --git a/doc/programming_guide/ffd/speech_recognition_sensory.rst b/doc/programming_guide/ffd/speech_recognition_sensory.rst index fe5e4f1e8..8d7b5f5e8 100644 --- a/doc/programming_guide/ffd/speech_recognition_sensory.rst +++ b/doc/programming_guide/ffd/speech_recognition_sensory.rst @@ -17,7 +17,7 @@ or 107 recognition events. Overview ======== -The Sensory THF speech recognition engine runs proprietary models to identify keywords in an audio stream. Models can be generated using `VoiceHub `__. +The Sensory THF speech recognition engine runs proprietary models to identify keywords in an audio stream. Models can be generated using `VoiceHub `__. Two models are provided - one in US English and one in Mainland Mandarin. The US English model is used by default. To modify the software to use the Mandarin model, see the comment at the top of the ``ffd_sensory.cmake`` file. Make sure run the following commands to rebuild and re-flash the data partition: @@ -26,7 +26,8 @@ Two models are provided - one in US English and one in Mainland Mandarin. The US make clean make flash_app_example_ffd_sensory -j -To replace the Sensory engine with a different engine, refer to the ASR documentation on :ref:`sln_voice_asr_programming_guide` +.. TODO: Check if the line below can be removed or re-added +.. To replace the Sensory engine with a different engine, refer to the ASR documentation on :ref:`sln_voice_asr_programming_guide` Dictionary command table ======================== diff --git a/doc/programming_guide/ffva/deploying/linux_macos.rst b/doc/programming_guide/ffva/deploying/linux_macos.rst index 117121bf1..126aee9a1 100644 --- a/doc/programming_guide/ffva/deploying/linux_macos.rst +++ b/doc/programming_guide/ffva/deploying/linux_macos.rst @@ -27,18 +27,29 @@ The host applications will be installed at ``/opt/xmos/bin``, and may be moved i Building the Firmware ===================== -Run the following commands in the root folder to build the |I2S| firmware: +After having your python environment activated, run the following commands in the root folder to build the |I2S| firmware: .. code-block:: console + pip install -r requirements.txt cmake -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build make example_ffva_int_fixed_delay -Run the following commands in the root folder to build the USB firmware: +After having your python environment activated, run the following commands in the root folder to build the |I2S| firmware with the Cyberon ASR engine: .. code-block:: console + pip install -r requirements.txt + cmake -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake + cd build + make example_ffva_int_cyberon_fixed_delay + +After having your python environment activated, run the following commands in the root folder to build the USB firmware: + +.. code-block:: console + + pip install -r requirements.txt cmake -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build make example_ffva_ua_adec_altarch @@ -53,6 +64,7 @@ Inside of the build folder root, after building the firmware, run one of: .. code-block:: console make flash_app_example_ffva_int_fixed_delay + make flash_app_example_ffva_int_cyberon_fixed_delay make flash_app_example_ffva_ua_adec_altarch Once flashed, the application will run. @@ -64,11 +76,15 @@ From the build folder run: .. code-block:: console xrun --xscope example_ffva_int_fixed_delay.xe + xrun --xscope example_ffva_int_cyberon_fixed_delay.xe xrun --xscope example_ffva_ua_adec_altarch.xe Upgrading the Firmware ====================== +UA variant +---------- + The UA variants of this application contain DFU over the USB DFU Class V1.1 transport method. To create an upgrade image from the build folder run: @@ -77,7 +93,7 @@ To create an upgrade image from the build folder run: make create_upgrade_img_example_ffva_ua_adec_altarch -Once the application is running, a USB DFU v1.1 tool can be used to perform various actions. This example will demonstrate with dfu-util commands. Installation instructions for respective operating system can be found `here `__ +Once the application is running, a USB DFU v1.1 tool can be used to perform various actions. This example will demonstrate with dfu-util commands. Installation instructions for the respective operating systems can be found `here `__. To verify the device is running run: @@ -115,7 +131,7 @@ The upgrade image can be read back by running: dfu-util -e -d ,20b1:4001 -a 1 -U readback_upgrade_img.bin -On system reboot, the upgrade image will always be loaded if valid. If the upgrade image is invalid, the factory image will be loaded. To revert back to the factory image, you can upload an file containing the word 0xFFFFFFFF. +On system reboot, the upgrade image will always be loaded if valid. If the upgrade image is invalid, the factory image will be loaded. To revert back to the factory image, you can upload a file containing the word 0xFFFFFFFF. The data partition image can be read back by running: @@ -131,6 +147,64 @@ The data partition image can be written by running: Note that the data partition will always be at the address specified in the initial flashing call. +INT variant +----------- + +The INT variants of this application contain DFU over |I2C|. + +To create an upgrade image from the build folder run: + +.. code-block:: console + + make create_upgrade_img_example_ffva_int_fixed_delay + +Once the application is running, the *xvf_dfu* tool can be used to perform various actions. Installation instructions for Raspbian OS can be found `here `__. + +Before running the *xvf_dfu* host application, the ``I2C_ADDRESS`` value in the file ``transport_config.yaml`` located in the same folder as the binary file ``xvf_dfu`` must be updated. This value must match the one set for ``appconf_CONTROL_I2C_DEVICE_ADDR`` in the ``platform_conf.h`` file. + +The DFU interprets the flash as 3 separate partitions, the read only factory image, the read/write upgrade image, and the read/write data partition containing the filesystem. + +The factory image can be read back by running: + +.. code-block:: console + + xvf_dfu --upload-factory readback_factory_img.bin + +The factory image can not be written to. + +From the build folder, the upgrade image can be written by running: + +.. code-block:: console + + xvf_dfu -d example_ffva_int_fixed_delay_upgrade.bin + +The upgrade image can be read back by running: + +.. code-block:: console + + xvf_dfu --upload-upgrade readback_upgrade_img.bin + +The device can be rebooted remotely by running + +.. code-block:: console + + xvf_dfu --reboot + +On system reboot, the upgrade image will always be loaded if valid. If the upgrade image is invalid, the factory image will be loaded. To revert back to the factory image, you can upload a file containing the word 0xFFFFFFFF. + +The FFVA-INT variants include some version numbers: + + - *APP_VERSION_MAJOR* + - *APP_VERSION_MINOR* + - *APP_VERSION_PATCH* + +These values are defined in the ``app_conf.h`` file, and they can read by running: + +.. code-block:: console + + xvf_dfu --version + +The data partition image cannot be read or write using the *xvf_dfu* host application. Debugging the Firmware ====================== diff --git a/doc/programming_guide/ffva/deploying/native_windows.rst b/doc/programming_guide/ffva/deploying/native_windows.rst index b297a4186..6de1e4d18 100644 --- a/doc/programming_guide/ffva/deploying/native_windows.rst +++ b/doc/programming_guide/ffva/deploying/native_windows.rst @@ -47,19 +47,29 @@ The host applications will be installed at ``%USERPROFILE%\.xmos\bin``, and may Building the Firmware ===================== -Run the following commands in the root folder to build the |I2S| firmware: +After having your python environment activated, run the following commands in the root folder to build the |I2S| firmware: .. code-block:: console + pip install -r requirements.txt cmake -G Ninja -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build ninja example_ffva_int_fixed_delay +After having your python environment activated, run the following commands in the root folder to build the |I2S| firmware with the Cyberon ASR engine: -Run the following commands in the root folder to build the USB firmware: +.. code-block:: console + + pip install -r requirements.txt + cmake -G Ninja -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake + cd build + ninja example_ffva_int_cyberon_fixed_delay + +After having your python environment activated, run the following commands in the root folder to build the USB firmware: .. code-block:: console + pip install -r requirements.txt cmake -G Ninja -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build ninja example_ffva_ua_adec_altarch @@ -74,6 +84,7 @@ Inside of the build folder root, after building the firmware, run one of: .. code-block:: console ninja flash_app_example_ffva_int_fixed_delay + ninja flash_app_example_ffva_int_cyberon_fixed_delay ninja flash_app_example_ffva_ua_adec_altarch Once flashed, the application will run. @@ -85,12 +96,14 @@ From the build folder run: .. code-block:: console xrun --xscope example_ffva_int_fixed_delay.xe + xrun --xscope example_ffva_int_cyberon_fixed_delay.xe xrun --xscope example_ffva_ua_adec_altarch.xe Upgrading the Firmware ====================== The UA variants of this application contain DFU over the USB DFU Class V1.1 transport method. +In this section DFU over |I2C| for the INT variants is not covered. The INT variants require an |I2C| connection to the host, and Windows doesn't support this feature. To create an upgrade image from the build folder run: diff --git a/doc/programming_guide/ffva/design.rst b/doc/programming_guide/ffva/design.rst index bab10acd9..6d2f9dd9a 100644 --- a/doc/programming_guide/ffva/design.rst +++ b/doc/programming_guide/ffva/design.rst @@ -16,46 +16,19 @@ INT requires |I2S| connections to the host. Refer to the schematic, connecting UA requires a USB connection to the host. -Single Controller Solution -========================== - -In a single controller solution, a user can populate the model runner manager task with the application specific code. - -This dummy thread receives only the ASR channel output, which has been downshifted to 16 bits. - -The user must ensure the streambuffer is emptied at the rate of the audio pipeline at minimum, otherwise samples will be lost. - -Populate: +Support for ASR engine +====================== -.. code-block:: c - :caption: Model Runner Dummy (model_runner.c) +The ``example_ffva_int_cyberon_fixed_delay`` provides an example about how to include an ASR engine, the Cyberon DSPotter™. - void model_runner_manager(void *args) - { - StreamBufferHandle_t input_queue = (StreamBufferHandle_t)args; +Most of the considerations made in the :ref:`section about the FFD devices` are still valid for the FFVA example. The only notable difference is that the pipeline output in the FFVA example +is on the same tile as the ASR engine, i.e. tile 0. - int16_t buf[appconfWW_FRAMES_PER_INFERENCE]; +.. note:: - /* Perform any initialization here */ + Both the audio pipeline and the ASR engine process use the same sample block length. ``appconfINTENT_SAMPLE_BLOCK_LENGTH`` and ``appconfAUDIO_PIPELINE_FRAME_ADVANCE`` are both 240. - while (1) - { - /* Receive audio frames */ - uint8_t *buf_ptr = (uint8_t*)buf; - size_t buf_len = appconfWW_FRAMES_PER_INFERENCE * sizeof(int16_t); - do { - size_t bytes_rxed = xStreamBufferReceive(input_queue, - buf_ptr, - buf_len, - portMAX_DELAY); - buf_len -= bytes_rxed; - buf_ptr += bytes_rxed; - } while(buf_len > 0); - - /* Perform inference here */ - // rtos_printf("inference\n"); - } - } +More information about the Cyberon engine can be found in :ref:`sln_voice_ffd_speech_recognition_cyberon` section. |newpage| @@ -70,4 +43,226 @@ The application consists of a PDM microphone input which is fed through the XMOS :scale: 80 % :alt: ffva diagram +.. _dfu_design: + +*********************************** +Device Firmware update (DFU) Design +*********************************** + +The Device Firmware Update (DFU) allows updating the firmware of the device from a host computer, +and it can be performed over |I2C| or USB. This interface closely follows the principles set out in +`version 1.1 of the Universal Serial Bus Device Class Specification for Device +Firmware Upgrade `_, including implementing +the state machine and command structure described there. + +The DFU process is internally managed by the DFU controller module within the firmware. +This module is tasked with overseeing the DFU state machine and executing DFU operations. +The list of states and transactions are represented in the diagram in :numref:`dfu_state_machine`. + +.. _dfu_state_machine: + +.. figure:: diagrams/dfu_state.drawio.png + :width: 100% + + State diagram of the DFU operations + +The main differences with the state diagram in `version 1.1 of Universal Serial Bus Device Class Specification for Device Firmware Upgrade `_ are: + + * the ``appIDLE`` and ``appDETACH`` states are not implemented, and the device is started in the ``dfuIDLE`` state + * the device goes into the ``dfuIDLE`` state when a ``SET_ALTERNATE`` message is received + * the device is rebooted when a ``DFU_DETACH`` command is received. + +The DFU allows the following operations: + + * download of an upgrade image to the device + * upload of factory and upgrade images from the device + * reboot of the device. + +The rest of this section describes the message sequence charts of the supported operations. + +A message sequence chart of the download operation is below: + +.. figure:: diagrams/dfu_download.plantuml.png + :width: 75% + + Message sequence chart of the download operation + +.. note:: + + The end of the image transfer is indicated by a ``DFU_DNLOAD`` message of size 0. + +.. note:: + + The ``DFU_DETACH`` message is used to trigger the reboot. + +.. note:: + + For the |I2C| implementation, specification of the block number in download is not supported; all downloads must start with block number 0 and must be run to completion. The device will track this progress internally. + +A message sequence chart of the reboot operation is below: + +.. figure:: diagrams/dfu_reboot.plantuml.png + + Message sequence chart of the reboot operation + +.. note:: + + The ``DFU_DETACH`` message is used to trigger the reboot. + +.. raw:: latex + + \newpage + +A message sequence chart of the upload operation is below: + +.. figure:: diagrams/dfu_upload.plantuml.png + :width: 75% + + Message sequence chart of the upload operation + +.. note:: + + The end of the image transfer is indicated by a ``DFU_UPLOAD`` message of size less than the transport medium maximum; this is 4096 bytes in UA and 128 bytes in INT. + +.. _dfu_usb_interface_design: + +DFU over USB implementation +=========================== + +The UA variant of the device makes use of a USB connection for handling DFU operations. +This interface is a relatively standard, specification-compliant implementation. +The implementation is encapsulated within the tinyUSB library, which provides a USB stack for the |project|. + +.. _dfu_i2c_interface_design: + +DFU over |I2C| implementation +============================= + +The INT variant of the device presents a DFU interface that may be controlled +over |I2C|. + +:numref:`fig_control_plane_components` shows the modules involved in +processing the DFU commands. The *I2C* task has a dedicated logical core so that it is always ready +to receive and send control messages. The DFU state machine is driven by the control commands. The DFU state +machine interacts with a separate RTOS task in +order to asynchronously perform flash read/write operations. + +.. _fig_control_plane_components: +.. figure:: diagrams/control_plane_components.drawio.png + :width: 50% + + |project| Control Plane Components Diagram + +.. raw:: latex + + \newpage + +:numref:`fig_control_plane_dc_servicer_flow_chart` shows the interaction +between the Device Control module and the DFU Servicer. +In this diagram, boxes with the same colour reside in the same RTOS task. + +.. _fig_control_plane_dc_servicer_flow_chart: +.. figure:: diagrams/control_plane_device_control_servicer_flow_chart.drawio.png + :width: 50% + + |project| Device Control -- Servicer Flow Chart + +This diagram shows a critical aspect of the DFU control operation. +The Device Control module, having placed a command on a Servicer's command +queue, waits on the Gateway queue for a response. +As a result, it ensures processing of a single control command at a time. +Limiting DFU control operation to a single command in-flight reduces the +complexity of the control protocol and eliminates several potential error +cases. + +The FFVA-INT uses a packet protocol to receive control commands and send each +corresponding response. +Because packet transmission occurs over a very short-haul transport, as in +|I2C|, the protocol does not include fields for error detection or correction such as start-of-frame and +end-of-frame symbols, a cyclical redundancy check or an error correcting code. +:numref:`fig_control_plane_packet` depicts the structure of each packet. + +.. _fig_control_plane_packet: +.. figure:: diagrams/control_plane_packet_diagram.drawio.png + :width: 100% + + |project| Control Plane Packet Diagram + +Packets containing a response from the FFVA-INT to the host application place +a status value in the first byte of the payload. + +Mirroring the USB DFU specification, the INT DFU implementation supports a set of 9 +control commands intended to drive the state machine, along with an additional 2 +utility commands: + +.. _tab_dfu_cmds: +.. csv-table:: DFU commands + :class: longtable + :file: ./tables/dfu_cmds_table.csv + :widths: 25, 3, 8, 24, 40 + :header-rows: 1 + +These commands are then used to drive the state machine described in the +:ref:`Device Firmware update (DFU) Design`. + +When writing a custom compliant host application, the use of XMOS' **fwk_rtos** +library is advised; the **device_control** library provided there gives a host +API that can communicate effectively with the FFVA-INT. A description of the |I2C| bus activity +during the execution of the above DFU commands is provided below, in the +instance that usage of the **device_control** library is inconvenient or +impossible. + +The FFVA-INT |I2C| address is set by default as 0x42. This may be +confirmed by examination of the ``appconf_CONTROL_I2C_DEVICE_ADDR`` define in the +``platform_conf.h`` file. The |I2C| address may also be altered by editing this file. +The DFU resource has an internal "resource ID" of 0xF0. This maps to the +register that read/write operations on the DFU resource should target - +therefore, the register to write to will always be 0xF0. + +To issue a write command (e.g. DFU_SETALTERNATE): + +* First, set up a write to the device address. For a default device + configuration, a write operation will always start by a write token to 0x42 + (START, 7 bits of address [0x42], R/W bit [0 to specify write]), wait for ACK, + followed by specifying the register to write [Resource ID 0xF0] + (and again wait for ACK). +* Then, write the command ID (in this example, 64 [0x40]) from the above table. +* Then, write the total transfer size, *including the register byte*. In this + example, that will be 4 bytes (register byte, command ID, length byte, and 1 + byte of payload), so write 0x04. +* Finally, send the payload - e.g. 1 to set the alternate setting to "upgrade". +* The full sequence for this write command will therefore be START, 7 bits of + address [0x42], 0 (to specify write), hold for ACK, 0xF0, hold for ACK, 0x40, + hold for ACK, 0x04, hold for ACK, 0x01, hold for ACK, STOP. +* To complete the transaction, the device must then be queried; set up a read to + 0x42 (START, 7 bits of address [0x42], R/W bit [1 to specify read], wait for + ACK). The device will clock-stretch until it is ready, at which point it will + release the clock and transmit one byte of status information. This will be a + value from the enum ``control_ret_t`` from ``device_control_shared.h``, + found in ``modules\rtos\modules\sw_services\device_control\api``. + +To issue a read command (e.g. DFU_GETSTATUS): + +* Set up a write to the device; as above, this will mean sending START, + 7 bits of device address [0x42], 0 (to specify write), hold for ACK. Send the + DFU resource ID [0xF0], hold for ACK. +* Then, write the command ID (in this example, 3), bitwise ANDed with 0x80 (to + specify this as a read command) - in this example therefore 0x83 should be + sent, and hold for ACK. +* Then, write the total length of the expected reply. In this example, the + command has a payload of 5 bytes. The device will also prepend the payload + with a status byte. Therefore, the expected reply length will be 6 bytes + [0x06]. Hold for ACK. +* Then, issue a repeated START. Follow this with a read from the device: + the repeated START, 7 bits of device address [0x42], 1 (to specify read), hold + for ACK. The device will clock-stretch until it is ready. It will then send + a status byte (from the enum ``control_ret_t`` as described above), followed + by a payload of requested data - in this example, the device will send 5 + bytes. ACK each received byte. After the last expected byte, issue a STOP. + +It is heavily advised that those wishing to write a custom host application to +drive the DFU process for the FFVA-INT over |I2C| familiarise themselves with +`version 1.1 of the Universal Serial Bus Device Class Specification for Device +Firmware Upgrade `_. + |newpage| diff --git a/doc/programming_guide/ffva/diagrams/control_plane_components.drawio b/doc/programming_guide/ffva/diagrams/control_plane_components.drawio new file mode 100644 index 000000000..53f3cf3d3 --- /dev/null +++ b/doc/programming_guide/ffva/diagrams/control_plane_components.drawio @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/programming_guide/ffva/diagrams/control_plane_components.drawio.png b/doc/programming_guide/ffva/diagrams/control_plane_components.drawio.png new file mode 100644 index 000000000..f7860fe10 Binary files /dev/null and b/doc/programming_guide/ffva/diagrams/control_plane_components.drawio.png differ diff --git a/doc/programming_guide/ffva/diagrams/control_plane_device_control_servicer_flow_chart.drawio b/doc/programming_guide/ffva/diagrams/control_plane_device_control_servicer_flow_chart.drawio new file mode 100644 index 000000000..82c783c28 --- /dev/null +++ b/doc/programming_guide/ffva/diagrams/control_plane_device_control_servicer_flow_chart.drawio @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/programming_guide/ffva/diagrams/control_plane_device_control_servicer_flow_chart.drawio.png b/doc/programming_guide/ffva/diagrams/control_plane_device_control_servicer_flow_chart.drawio.png new file mode 100644 index 000000000..42e360f65 Binary files /dev/null and b/doc/programming_guide/ffva/diagrams/control_plane_device_control_servicer_flow_chart.drawio.png differ diff --git a/doc/programming_guide/ffva/diagrams/control_plane_packet_diagram.drawio b/doc/programming_guide/ffva/diagrams/control_plane_packet_diagram.drawio new file mode 100644 index 000000000..1e0217dcd --- /dev/null +++ b/doc/programming_guide/ffva/diagrams/control_plane_packet_diagram.drawio @@ -0,0 +1 @@ +7Zldb5swFIZ/TaTtohVfIXCZJu3WqZW6VtO63UweOEAHmBkngf76mWC+jGnSFLpU6U1rH5vj4/O8NuhkpM6C5BMGkXuNbOiPFMlORup8pCiGqdO/mSHNDaph5AYHe3ZukivDnfcImVFi1qVnw7gxkSDkEy9qGi0UhtAiDRvAGK2b0xbIb64aAQe2DHcW8NvW755NXGbVx1o18Bl6jlssLetmPhKAYjbbSuwCG61rJvV8pM4wQiRvBckM+lnyisTkz110jJaRYRiSXR5YKCtwnz58fYx+/rq0rh6+Xd9+OWFeVsBfsh2PFN2n/s4WiLqlUZOU5UL/u0TFwEm8ITWlExQtSqpB2nKy/7cwRktsQTrhcl64/I2L4Q90/HL+sRigQefL5aMsX+XKCkbL0IbZPiQ6vHY9Au8iYGWjayo7anNJ4NOeXD69gpjApDNVcgmAKheiABKc0inFAzpjxlSraKy/rmuA2dw6/sIImO6c0ndFhjYYnGeAUgYCNUNBAEK7i9MssA+Yk6ocHCe1k1McgXB/Tjcg9RHIOF3B0KGbq5Dkjg8EiWYcHBJNgITLEgztafa2oL0QhbCZFZh45L7W/sGSmbXnSb2Tsk7uH9qtdwuXRRpDfktu0VM727VsjgXJLGwY+oB4q2YYogSzFW6Qt7lMOu5BbcIxysNnT9XfPZwjQ+pQReGIAOxA0nK04V1ue38JjA9WAv8Lra5xaKWe0LYcDYxWf0fLETG7vl6ei1aWu96vr8R28s52C9u9j22L7WufW+OFbA+d1PYEv5ljaG5HZS3xavOVuTlqT57J0L7wsvXfxHmbmFzq+a/UnV+TMudI2Y0hTSRIa9OibELcHXBrHV16Mq7WBptVBNrII+hVUEWMx6gocyz3oyhzIgvJ9a2o1jpbFNXa4KsoSlTIOhJFTcxmwjVeCLvfUU1HqjHUHSUOuPuOEsc1rKKU41WUOZaEgPa4oyQhuf7vKHHA3XeUOK5hFdVdG3xZDbesDe5WpSUwIU11xgSjP3CGfIQr9S6oXjkT8D0npF2LyhRS+1lWKvQs4E/ZQODZdraMsNDYLEWyXLyk1mio3LdL8WtTvdYoCY4J//3cW6lRFtUa+0B8enp6fHj5OobcxqsJ6KqD0RWVEd/p9kNXnQxGl3arn1nz27z6sVo9/wc= \ No newline at end of file diff --git a/doc/programming_guide/ffva/diagrams/control_plane_packet_diagram.drawio.png b/doc/programming_guide/ffva/diagrams/control_plane_packet_diagram.drawio.png new file mode 100644 index 000000000..7588cd356 Binary files /dev/null and b/doc/programming_guide/ffva/diagrams/control_plane_packet_diagram.drawio.png differ diff --git a/doc/programming_guide/ffva/diagrams/dfu_download.plantuml b/doc/programming_guide/ffva/diagrams/dfu_download.plantuml new file mode 100644 index 000000000..4fa6c2562 --- /dev/null +++ b/doc/programming_guide/ffva/diagrams/dfu_download.plantuml @@ -0,0 +1,24 @@ +@startuml +participant Host as H +participant Device as D +H -> D : SET_INTERFACE (ALT=1) +D --> H +H -> D : DFU_GETSTATUS +D --> H : Status=OK, State=dfuIDLE, Timeout=0ms +loop until image is complete: n from 0 to N-1 + H -> D : DFU_DNLOAD (BlockNum=n, Size>0) + D --> H + H -> D : DFU_GETSTATUS + D --> H : Status=OK, State=dfuDNBUSY, Timeout=10ms + H -> D : DFU_GETSTATUS + D --> H : Status=OK, State=dfuDNLOAD-IDLE, Timeout=0ms +end +H -> D : DFU_DNLOAD (BlockNum=N, Size=0) +D --> H +H -> D : DFU_GETSTATUS +D --> H : Status=OK, State=dfuMANIFEST +H -> D : DFU_GETSTATUS +D --> H : Status=OK, State=dfuIDLE, Timeout=0ms +H -> D : DFU_DETACH +D --> H +@enduml diff --git a/doc/programming_guide/ffva/diagrams/dfu_download.plantuml.png b/doc/programming_guide/ffva/diagrams/dfu_download.plantuml.png new file mode 100644 index 000000000..8abb70db6 Binary files /dev/null and b/doc/programming_guide/ffva/diagrams/dfu_download.plantuml.png differ diff --git a/doc/programming_guide/ffva/diagrams/dfu_reboot.plantuml b/doc/programming_guide/ffva/diagrams/dfu_reboot.plantuml new file mode 100644 index 000000000..172c7cae5 --- /dev/null +++ b/doc/programming_guide/ffva/diagrams/dfu_reboot.plantuml @@ -0,0 +1,10 @@ +@startuml +participant Host as H +participant Device as D +H -> D : SET_INTERFACE (ALT=0) +D --> H +H -> D : DFU_GETSTATUS +D --> H : Status=OK, State=dfuIDLE, Timeout=0ms +H -> D : DFU_DETACH +D --> H +@enduml diff --git a/doc/programming_guide/ffva/diagrams/dfu_reboot.plantuml.png b/doc/programming_guide/ffva/diagrams/dfu_reboot.plantuml.png new file mode 100644 index 000000000..b5d1b407f Binary files /dev/null and b/doc/programming_guide/ffva/diagrams/dfu_reboot.plantuml.png differ diff --git a/doc/programming_guide/ffva/diagrams/dfu_state.drawio b/doc/programming_guide/ffva/diagrams/dfu_state.drawio new file mode 100644 index 000000000..04d82e7f8 --- /dev/null +++ b/doc/programming_guide/ffva/diagrams/dfu_state.drawio @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/programming_guide/ffva/diagrams/dfu_state.drawio.png b/doc/programming_guide/ffva/diagrams/dfu_state.drawio.png new file mode 100644 index 000000000..b1e1f8c55 Binary files /dev/null and b/doc/programming_guide/ffva/diagrams/dfu_state.drawio.png differ diff --git a/doc/programming_guide/ffva/diagrams/dfu_upload.plantuml b/doc/programming_guide/ffva/diagrams/dfu_upload.plantuml new file mode 100644 index 000000000..461a60f20 --- /dev/null +++ b/doc/programming_guide/ffva/diagrams/dfu_upload.plantuml @@ -0,0 +1,14 @@ +@startuml +participant Host as H +participant Device as D +H -> D : SET_INTERFACE (ALT=0) +D --> H +H -> D : DFU_GETSTATUS +D --> H : Status=OK, State=dfuIDLE, Timeout=0ms +loop until image is complete: n from 0 to N-1 + H -> D : DFU_UPLOAD (BlockNum=n) + D --> H : Data, Size>0 +end +H -> D : DFU_UPLOAD (BlockNum=N) +D --> H : Data, Size=0 +@enduml diff --git a/doc/programming_guide/ffva/diagrams/dfu_upload.plantuml.png b/doc/programming_guide/ffva/diagrams/dfu_upload.plantuml.png new file mode 100644 index 000000000..f9b69ae3d Binary files /dev/null and b/doc/programming_guide/ffva/diagrams/dfu_upload.plantuml.png differ diff --git a/doc/programming_guide/ffva/software_desc/bsp_config.rst b/doc/programming_guide/ffva/software_desc/bsp_config.rst index ff5da13dd..ee179b7d9 100644 --- a/doc/programming_guide/ffva/software_desc/bsp_config.rst +++ b/doc/programming_guide/ffva/software_desc/bsp_config.rst @@ -1,8 +1,8 @@ .. _sln_voice_ffva_bsp_config: -########## -bsp_config -########## +######################## +examples/ffva/bsp_config +######################## This folder contains bsp_configs for the FFVA application. More information on bsp_configs can be found in the RTOS Framework documentation. diff --git a/doc/programming_guide/ffva/software_desc/filesystem_support.rst b/doc/programming_guide/ffva/software_desc/filesystem_support.rst index 029e1920f..a08838e00 100644 --- a/doc/programming_guide/ffva/software_desc/filesystem_support.rst +++ b/doc/programming_guide/ffva/software_desc/filesystem_support.rst @@ -1,8 +1,8 @@ .. _sln_voice_ffva_filesystem_support: -################## -filesystem_support -################## +################################ +examples/ffva/filesystem_support +################################ This folder contains filesystem contents for the FFVA application. diff --git a/doc/programming_guide/ffva/software_desc/overview.rst b/doc/programming_guide/ffva/software_desc/overview.rst index 802b4b96b..e07968156 100644 --- a/doc/programming_guide/ffva/software_desc/overview.rst +++ b/doc/programming_guide/ffva/software_desc/overview.rst @@ -4,7 +4,7 @@ Overview ******** -There are two main build configurations for this application. +There are three main build configurations for this application. .. list-table:: FFVA INT Fixed Delay Resources :widths: 30 10 30 @@ -14,15 +14,27 @@ There are two main build configurations for this application. * - Resource - Tile 0 - Tile 1 - * - Unused CPU Time (600 MHz) - - 98% - - 75% * - Total Memory Free - - 166k - - 82k + - 141k + - 80k * - Runtime Heap Memory Free - 75k - - 82k + - 76k + +.. list-table:: FFVA INT Cyberon Fixed Delay Resources + :widths: 30 10 30 + :header-rows: 1 + :align: left + + * - Resource + - Tile 0 + - Tile 1 + * - Total Memory Free + - 21k + - 79k + * - Runtime Heap Memory Free + - 19k + - 81k .. list-table:: FFVA UA ADEC Resources :widths: 30 10 30 @@ -32,12 +44,9 @@ There are two main build configurations for this application. * - Resource - Tile 0 - Tile 1 - * - Unused CPU Time (600 MHz) - - 83% - - 45% * - Total Memory Free - - 123k - - 58k + - 94k + - 59k * - Runtime Heap Memory Free - 54k - 83k @@ -58,4 +67,8 @@ The description of the software is split up by folder: * - :ref:`sln_voice_ffva_filesystem_support` - Filesystem contents for application * - :ref:`sln_voice_ffva_src` - - Main application \ No newline at end of file + - Main application + * - :ref:`sln_voice_intent_engine` + - Intent engine integration (FFVA INT Cyberon only) + * - :ref:`sln_voice_intent_handler` + - Intent engine output integration (FFVA INT Cyberon only) \ No newline at end of file diff --git a/doc/programming_guide/ffva/software_desc/src.rst b/doc/programming_guide/ffva/software_desc/src.rst index f8a99e69b..f23728e20 100644 --- a/doc/programming_guide/ffva/software_desc/src.rst +++ b/doc/programming_guide/ffva/software_desc/src.rst @@ -1,9 +1,9 @@ .. _sln_voice_ffva_src: -### -src -### +################# +examples/ffva/src +################# This folder contains the core application source. diff --git a/doc/programming_guide/ffva/software_modifications.rst b/doc/programming_guide/ffva/software_modifications.rst index 28b870191..a9341cfe5 100644 --- a/doc/programming_guide/ffva/software_modifications.rst +++ b/doc/programming_guide/ffva/software_modifications.rst @@ -144,45 +144,10 @@ With: It is also possible to add or remove stages. Refer to the RTOS Framework documentation on the generic pipeline sw_service. -Populating a Keyword Engine Block -------------------------------------- - -To add a keyword engine block, a user may populate the existing ``model_runner_manager()`` function with their model: - -.. code-block:: c - :caption: Model Runner (model_runner.c) - - configSTACK_DEPTH_TYPE model_runner_manager_stack_size = 287; - - void model_runner_manager(void *args) - { - StreamBufferHandle_t input_queue = (StreamBufferHandle_t)args; - - int16_t buf[appconfWW_FRAMES_PER_INFERENCE]; - - /* Perform any initialization here */ - - while (1) - { - /* Receive audio frames */ - uint8_t *buf_ptr = (uint8_t*)buf; - size_t buf_len = appconfWW_FRAMES_PER_INFERENCE * sizeof(int16_t); - do { - size_t bytes_rxed = xStreamBufferReceive(input_queue, - buf_ptr, - buf_len, - portMAX_DELAY); - buf_len -= bytes_rxed; - buf_ptr += bytes_rxed; - } while(buf_len > 0); - - /* Perform inference here */ - // rtos_printf("inference\n"); - } - } - -Populate initialization and inference engine calls where commented. After adding user code, the stack size of the task will need to be adjusted accordingly based on the engine being used. The input streambuffer must be emptied at least at the rate of the audio pipeline otherwise frames will be lost. +Changing the ASR engine +----------------------- +THE FFVA provides an example with a specific ASR engine. A different ASR engine can be used by updating and adding the necessary files in ``modules\asr``. Replacing Example Design Interfaces ----------------------------------- diff --git a/doc/programming_guide/ffva/tables/dfu_cmds_table.csv b/doc/programming_guide/ffva/tables/dfu_cmds_table.csv new file mode 100644 index 000000000..ccbcbce22 --- /dev/null +++ b/doc/programming_guide/ffva/tables/dfu_cmds_table.csv @@ -0,0 +1,12 @@ +"Name","ID","Length","Payload Structure","Purpose" +"DFU_DETACH",0,1,"Payload unused","Write-only command. Restarts the device. Payload is required for protocol, but is discarded within the device. This command has a defined purpose in the USB DFU specification, but in a deviation to that specification it is used with |I2C| simply to reboot the device. Future versions of the XMOS DFU-by-device-control protocol (but not future versions of this product) may choose to alter the function of this command to more closely align with the USB DFU specification." +"DFU_DNLOAD",1,130,"2 bytes length marker, followed by 128 bytes of data buffer","Write-only command. The first two bytes indicate how many bytes of data are being transmitted in this packet. These bytes are little-endian, so byte 0 represents the low byte and byte 1 represents the high byte of an unsigned 16b integer. The remaining 128 bytes are a data buffer for transfer to the device. All control command packets are a fixed length, and therefore all 128 bytes must be included in the command, even if unused. For example, a payload with length of 100 should have the first 100 bytes of data set, but must send an additional 28 bytes of arbitrary data." +"DFU_UPLOAD",2,130,"2 bytes length marker, followed by 128 bytes of data buffer","Read-only command. The first two bytes indicate how many bytes of data are being transmitted in this packet. These bytes are little-endian, so byte 0 represents the low byte and byte 1 represents the high byte of an unsigned 16b integer. The remaining 128 bytes are a data buffer of data received from the device. All control command packets are a fixed length, and therefore this buffer will be padded to length 128 by the device before transmission. The device will, as per the USB DFU specification, mark the end of the upload process by sending a ""short frame"" - a packet with a length marker less than 128 bytes." +"DFU_GETSTATUS",3,5,"1 byte representing device status, 3 bytes representing the requested timeout, 1 byte representing the next device state.","Read-only command. The first byte returns the device status code, as described in the USB DFU specification in the table in section 6.1.2. The next 3 bytes represent the amount of time the host should wait, in ms, before issuing any other commands. This timeout is used in the DNLOAD process to allow the device time to write to flash. This value is little-endian, so bytes 1, 2, and 3 represent the low, middle, and high bytes respectively of an unsigned 24b integer. The final byte returns the number of the state that the device will move into immediately following the return of this request, as described in the USB DFU specification in the table in section 6.1.2." +"DFU_CLRSTATUS",4,1,"Payload unused","Write-only command. Moves the device out of state 10, dfuERROR. Payload is required for protocol, but is discarded within the device." +"DFU_GETSTATE",5,1,"1 byte representing current device state.","Read-only command. The first (and only) byte represents the number of the state that the device is currently in, as described in the USB DFU specification in the table in section 6.1.2." +"DFU_ABORT",6,1,"Payload unused","Write-only command. Aborts an ongoing upload or download process. Payload is required for protocol, but is discarded within the device." +"DFU_SETALTERNATE",64,1,"1 byte representing either factory (0) or upgrade (1) DFU target images","Write-only command. Sets which of the factory or upgrade images should be targeted by any subsequent upload or download commands. Use of this command entirely resets the DFU state machine to initial conditions: the device will move to dfuIDLE, clear all error conditions, wipe all internal DFU data buffers, and reset all other DFU state apart from the DFU_TRANSFERBLOCK value. This command is included to emulate the SET_ALTERNATE request available in USB." +"DFU_TRANSFERBLOCK",65,2,"2 bytes, representing the target transfer block for an upload process.","Read/write command. Sets/gets a 2 byte value specifying the transfer block number to use for a subsequent upload operation. A complete image may be conceptually divided into 128-byte blocks. These blocks may then be numbered from 0 upwards. Setting this value sets which block will be returned by a subsequent DFU_UPLOAD request. This value is initialised to 0, and autoincrements after each successful DFU_UPLOAD request has been serviced. Therefore, to read a whole image from the start, there is no need to issue this command - this command need only be used to select a specific section to read. Because this value is automatically incremented after a DFU_UPLOAD command is successfully serviced, reading it will give the value of the next block to be read (and this will be one greater than the previous block read, if it has not been altered in the interim). This value is reset to 0 at the successful completion of a DFU_UPLOAD process. It is not reset after a DFU_ABORT, nor after a DFU_SETALTERNATE call. This command is included to emulate the ability in a USB request to send values in the header of the request - the device control protocol used here does not allow sending any data with a read request such as DFU_UPLOAD." +"DFU_GETVERSION",88,3,"3 bytes, representing major.minor.patch version of device","Read-only command. Bytes 0, 1, and 2 represent the major, minor, and patch versions respectively of the device. This is a utility command intended to provide an easy mechanism by which to verify that a firmware download has been successful." +"DFU_REBOOT",89,1,"Payload unused","Write-only command. Restarts the device. Payload is required for protocol, but is discarded within the device. This is a utility command intended to provide a clear and unambiguous interface for restarting the device. Use of this command should be preferred over DFU_DETACH for this purpose." diff --git a/doc/programming_guide/howto.rst b/doc/programming_guide/howto.rst index 40be93261..4bd333498 100644 --- a/doc/programming_guide/howto.rst +++ b/doc/programming_guide/howto.rst @@ -15,7 +15,7 @@ In the example design ``app_conf.h`` file, change ``appconfAUDIO_PIPELINE_SAMPLE |I2S| AEC reference input audio & USB processed audio output ************************************************************ -The FFVA example design includes 2 basic configurations; INT and UA. The INT configuration is setup with |I2S| for input and output audio. The UA configuration is setup with USB for input and output audio. This HOWTO explains how to modify the FFVA example design for |I2S| input audio and USB output audio. +The FFVA example design includes 2 basic configurations; INT and UA. The INT configuration is setup with |I2S| for input and output audio. The UA configuration is setup with USB for input and output audio. This HOWTO explains how to modify the FFVA example design for |I2S| input audio and USB output audio. In the ``ffva_ua.cmake`` file, changing the ``appconfAEC_REF_DEFAULT`` to ``appconfAEC_REF_I2S`` will result in the expected input frames. @@ -31,7 +31,7 @@ In the ``ffva_ua.cmake`` file, changing the ``appconfAEC_REF_DEFAULT`` to ``appc MIC_ARRAY_CONFIG_MCLK_FREQ=24576000 ) -For integrating with |I2S| there are a few other differences from the default UA configuration. FFVA was designed to be integrated with an Raspberry Pi for an AVS demo. And, due to that the INT config uses an externally generated ``MCLK``. When integrating with an external Raspberry Pi ``MCLK``, you will want the following ``FFVA_UA_COMPILE_DEFINITIONS``: +For integrating with |I2S| there are a few other differences from the default UA configuration. When integrating with an external Raspberry Pi ``BCLK`` and ``LRCLK``, you will want the following ``FFVA_UA_COMPILE_DEFINITIONS``: .. code-block:: cmake @@ -43,16 +43,16 @@ For integrating with |I2S| there are a few other differences from the default UA appconfAEC_REF_DEFAULT=appconfAEC_REF_I2S appconfI2S_MODE=appconfI2S_MODE_SLAVE - appconfEXTERNAL_MCLK=1 + appconfEXTERNAL_MCLK=0 appconfI2S_AUDIO_SAMPLE_RATE=48000 MIC_ARRAY_CONFIG_MCLK_FREQ=12288000 ) ``appconfI2S_AUDIO_SAMPLE_RATE`` can also be 16000. Only 48k and 16k conversions is supported in FFVA. -If you enable ``appconfEXTERNAL_MCLK``, the FFVA example application will sit at initialization until we can lock on to that clock source, so it MUST be active during boot. +The default FFVA INT device doesn't require an external ``MCLK``, but this setting can be changed by setting ``appconfEXTERNAL_MCLK=1``. In this case the FFVA example application will sit at initialization until it can lock on to that clock source, so it MUST be active during boot. -Since the FFVA example application is not receiving reference audio through USB in this configuration, USB adaptive mode will not adapt to the input. By default, ffva will output the configured nominal rate. +Since the FFVA example application is not receiving reference audio through USB in this configuration, USB adaptive mode will not adapt to the input. By default, FFVA will output the configured nominal rate. If you enable ``appconfAEC_REF_DEFAULT=appconfAEC_REF_I2S`` and ``appconfI2S_MODE=appconfI2S_MODE_MASTER``. You need to invert ``I2S_DATA_IN`` and ``I2S_MIC_DATA`` in the ``bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn`` file to have the reference audio play properly. diff --git a/doc/programming_guide/low_power_ffd/deploying/configuration.rst b/doc/programming_guide/low_power_ffd/deploying/configuration.rst index 4faabefa1..1cb88de9d 100644 --- a/doc/programming_guide/low_power_ffd/deploying/configuration.rst +++ b/doc/programming_guide/low_power_ffd/deploying/configuration.rst @@ -13,7 +13,7 @@ variables to the APP_COMPILE_DEFINITIONS CMake variable located in the example's If options are changed, the application firmware must be rebuilt. .. list-table:: Low Power FFD Compile Options - :widths: 90 85 20 + :widths: 48 42 10 :header-rows: 1 :align: left @@ -26,13 +26,13 @@ If options are changed, the application firmware must be rebuilt. * - appconfINTENT_UART_OUTPUT_ENABLED - Enables/disables the UART intent message - 1 - * - appconfINTENT_I2C_OUTPUT_ENABLED - - Enables/disables the |I2C| intent message + * - appconfINTENT_I2C_MASTER_OUTPUT_ENABLED + - Enables/disables sending the intent message over |I2C| master - 1 * - appconfUART_BAUD_RATE - Sets the baud rate for the UART tx intent interface - 9600 - * - appconfINTENT_I2C_OUTPUT_DEVICE_ADDR + * - appconfINTENT_I2C_MASTER_DEVICE_ADDR - Sets the |I2C| slave address to transmit the intent to - 0x01 * - appconfINTENT_TRANSPORT_DELAY_MS diff --git a/doc/programming_guide/low_power_ffd/deploying/linux_macos.rst b/doc/programming_guide/low_power_ffd/deploying/linux_macos.rst index fda2f1582..230e402ec 100644 --- a/doc/programming_guide/low_power_ffd/deploying/linux_macos.rst +++ b/doc/programming_guide/low_power_ffd/deploying/linux_macos.rst @@ -29,10 +29,11 @@ wish to add this directory to your ``PATH`` variable. Building the Firmware ===================== -Run the following commands in the root folder to build the firmware: +After having your python environment activated, run the following commands in the root folder to build the firmware: .. code-block:: console + pip install -r requirements.txt cmake -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build make example_low_power_ffd_sensory diff --git a/doc/programming_guide/low_power_ffd/deploying/native_windows.rst b/doc/programming_guide/low_power_ffd/deploying/native_windows.rst index 7fbb8dcd7..5e0221327 100644 --- a/doc/programming_guide/low_power_ffd/deploying/native_windows.rst +++ b/doc/programming_guide/low_power_ffd/deploying/native_windows.rst @@ -53,10 +53,11 @@ You may wish to add this directory to your ``PATH`` variable. Building the Firmware ===================== -Run the following commands in the root folder to build the firmware: +After having your python environment activated, run the following commands in the root folder to build the firmware: .. code-block:: console + pip install -r requirements.txt cmake -G Ninja -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake cd build ninja example_low_power_ffd_sensory diff --git a/doc/programming_guide/low_power_ffd/software_desc/intent_engine.rst b/doc/programming_guide/low_power_ffd/software_desc/intent_engine.rst index d94be5823..f22253102 100644 --- a/doc/programming_guide/low_power_ffd/software_desc/intent_engine.rst +++ b/doc/programming_guide/low_power_ffd/software_desc/intent_engine.rst @@ -68,7 +68,7 @@ samples at startup. :caption: intent_engine_create snippet (intent_engine_io.c) int sync = 0; - #if ON_TILE(AUDIO_PIPELINE_TILE_NO) + #if ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) size_t len = rtos_intertile_rx_len(intertile_ctx, appconfINTENT_ENGINE_READY_SYNC_PORT, RTOS_OSAL_WAIT_FOREVER); xassert(len == sizeof(sync)); rtos_intertile_rx_data(intertile_ctx, &sync, sizeof(sync)); diff --git a/doc/programming_guide/low_power_ffd/software_desc/overview.rst b/doc/programming_guide/low_power_ffd/software_desc/overview.rst index 2148205af..668a40b08 100644 --- a/doc/programming_guide/low_power_ffd/software_desc/overview.rst +++ b/doc/programming_guide/low_power_ffd/software_desc/overview.rst @@ -44,7 +44,7 @@ added code and/or user added compile options. The description of the software is split up by folder: .. list-table:: Low Power FFD Software Description - :widths: 40 120 + :widths: 40 60 :header-rows: 1 :align: left diff --git a/doc/programming_guide/low_power_ffd/speech_recognition.rst b/doc/programming_guide/low_power_ffd/speech_recognition.rst index 760d1cd1a..74e49f167 100644 --- a/doc/programming_guide/low_power_ffd/speech_recognition.rst +++ b/doc/programming_guide/low_power_ffd/speech_recognition.rst @@ -17,7 +17,7 @@ or 107 recognition events. Overview ======== -The Sensory THF speech recognition engine runs proprietary models to identify keywords in an audio stream. Models can be generated using `VoiceHub `__. +The Sensory THF speech recognition engine runs proprietary models to identify keywords in an audio stream. Models can be generated using `VoiceHub `__. Two models are provided for the purpose of Low Power FFD. The small wake word model running on tile 1 is approximately 67KB. The command model running on tile 0 is approximately 289KB. On tile 1, the @@ -37,13 +37,14 @@ To run with a different model, see the ``Set Sensory model variables`` section o Make sure run the following commands to rebuild and re-flash the data partition: .. code-block:: console - + make clean make flash_app_example_low_power_ffd -j You may also wish to modify the command ID-to-string lookup table which is located in the ``src/intent_engine/intent_engine_io.c`` source file. -To replace the Sensory engine with a different engine, refer to the ASR documentation on :ref:`sln_voice_asr_programming_guide` +.. TODO: Check if the line below can be removed or re-added +.. To replace the Sensory engine with a different engine, refer to the ASR documentation on :ref:`sln_voice_asr_programming_guide` Wake Word Dictionary ==================== diff --git a/doc/programming_guide/mic_aggregator/mic_aggregator.rst b/doc/programming_guide/mic_aggregator/mic_aggregator.rst index 478974e4e..ff7b556cd 100644 --- a/doc/programming_guide/mic_aggregator/mic_aggregator.rst +++ b/doc/programming_guide/mic_aggregator/mic_aggregator.rst @@ -7,10 +7,10 @@ Operation ========= The design consists of a number of tasks connected via the xcore-ai silicon communication channels. -The decimators in the microphone array are configured to produce a 48 kHz PCM output. +The decimators in the microphone array are configured to produce a 48 kHz PCM output. The 16 output channels are loaded into a 16 slot TDM slave peripheral running at 24.576 MHz bit clock or a USB Audio Class 2 asynchronous interface and are optionally -amplified. The TDM build also provides a simple I2C slave interface to allow +amplified. The TDM build also provides a simple |I2C| slave interface to allow gains to be controlled at run-time. The USB build supports USB Audio Class 2 compliant volume controls. For the TDM build, a simple TDM16 master peripheral is included as well as a local @@ -42,13 +42,13 @@ xcore-ai architecture. The thread diagrams are shown in :numref:`agg_tdm` and :n PDM Capture ----------- -Both the TDM and USB aggregator examples share a common PDM front end. This consists of an 8 bit port +Both the TDM and USB aggregator examples share a common PDM front end. This consists of an 8 bit port with each data line connected to two PDM microphones each configured to provide data on a different clock edge. The 3.072 MHz clock for the PDM microphones is provided by the xcore-ai device on a 1 bit port and clocks all PDM microphones. The PDM clock is divided down from the 24.576 MHz local MCLK. -The data collected by the 8 bit port is sent to the lib_mic_array block which de-interleaves +The data collected by the 8 bit port is sent to the lib_mic_array block which de-interleaves the PDM data streams and performs decimation of the PDM data down to 48 kHz 32 bit PCM samples. Due to the large number of microphones the PDM capture stage uses four hardware threads on tile[0]; one for the microphone capture and three for decimation. This is needed to divide the processing workload and meet timing comfortably. @@ -62,11 +62,11 @@ Audio Hub The 16 channels of 48 kHz PCM streams are collected by `Hub` and are amplified using a saturated gain stage. The initial gain is set to 100, since a gain of 1 sounds very quiet due to the mic_array output being scaled to allow acoustic -overload of the microphones without clipping within the decimators. This value can be +overload of the microphones without clipping within the decimators. This value can be overridden using the ``MIC_GAIN_INIT`` define in `app_conf.h`. Additionally for the TDM configuration, the `Hub` task also checks for control packets -from I2C which may be used to dynamically update the individual gains at runtime. +from |I2C| which may be used to dynamically update the individual gains at runtime. A single hardware thread contains the task and a triple buffer scheme is used to ensure there is always a free buffer available to write into regardless of the relative phase between the production @@ -80,9 +80,9 @@ TDM Host Connection ------------------- The TDM build supports a 16-slot TDM slave Tx peripheral from the fwk_io sub-module. In this application -it runs at 24.576 MHz bit clock which supports 16 channels of 32 bit, 48 kHz samples per frame. +it runs at 24.576 MHz bit clock which supports 16 channels of 32 bit, 48 kHz samples per frame. -The TDM component uses a single hardware thread. +The TDM component uses a single hardware thread. For the purpose of debugging a simple TDM 16 Master Rx component is provided. This allows the transmitted TDM frames from the application to be received and checked without having to connect an external @@ -113,7 +113,7 @@ Resource Usage ============== The xcore-ai device has a total resource count of 2 x 524288 Bytes of memory and 2 x 8 hardware threads across two tiles. -This application uses around half of the processing resources and a tiny fraction of the available memory +This application uses around half of the processing resources and a tiny fraction of the available memory meaning there is plenty of space inside the chip for additional functionality if needed. TDM Build @@ -124,7 +124,7 @@ Tile Memory Threads ===== ======== ======= 0 25996 5 1 22812 2* -Total 48808 7 +Total 48808 7 ===== ======== ======= * An additional debug TDM Master thread is used on Tile[1] by default which is not needed in a practical deployment. @@ -137,7 +137,7 @@ Tile Memory Threads ===== ======== ======= 0 24252 4 1 52116 5 -Total 76368 9 +Total 76368 9 ===== ======== ======= @@ -171,7 +171,7 @@ Mic pair J14 pin 7, 15 21 ======== ======= -For I2C control, make the following connections: +For |I2C| control, make the following connections: =============== ================ Host Connection Board Connection @@ -181,7 +181,7 @@ SDA IOL Your I2C host SDA. GND Your I2C host ground. =============== ================ -The I2C slave is tested at 100 kHz SCL. +The |I2C| slave is tested at 100 kHz SCL. I2C Controlled Volume ===================== @@ -233,7 +233,7 @@ Register Value 31 Channel 15 lower gain byte ======== ========================== -If using a raspberry Pi as the I2C host you may use the following +If using a raspberry Pi as the |I2C| host you may use the following commands: :: diff --git a/doc/programming_guide/prerequisites.rst b/doc/programming_guide/prerequisites.rst index 1c09257e5..34b1c7b18 100644 --- a/doc/programming_guide/prerequisites.rst +++ b/doc/programming_guide/prerequisites.rst @@ -4,7 +4,7 @@ Prerequisites ############# -It is recommended that you download and install the latest release of the `XTC Tools `__. XTC Tools 15.2.1 or newer are required for building, running, flashing and debugging the example applications. +It is recommended that you download and install the latest release of the `XTC Tools `__. XTC Tools |TOOLS_VERSION| or newer are required for building, running, flashing and debugging the example applications. `CMake 3.21 `_ or newer and `Git `_ are also required for building the example applications. @@ -14,7 +14,7 @@ Windows A standard C/C++ compiler is required to build applications for the host PC. Windows users may use `Build Tools for Visual Studio `__ command-line interface. -It is highly recommended to use *Ninja* as the build system for native Windows firmware builds. +It is recommended to use *Ninja* as the build system for native Windows firmware builds. To install *Ninja* follow install instructions at https://ninja-build.org/ or on Windows install with ``winget`` by running the following commands in *PowerShell*: diff --git a/doc/quick_start_guide/index.rst b/doc/quick_start_guide/index.rst index 762fcaf60..3afcd4a58 100644 --- a/doc/quick_start_guide/index.rst +++ b/doc/quick_start_guide/index.rst @@ -18,5 +18,7 @@ XCORE-VOICE Quick Start Guide Other examples ************** -Where no quickstart guide exists such as for :ref:`Microphone Aggregation ` and :ref:`Automatic Speech Recognition ` please constult the :ref:`Programming Guide ` which contains setup information for these applications. +Where no quickstart guide exists such as for :ref:`Microphone Aggregation `, +:ref:`Asynchronous Sample Rate Conversion ` and :ref:`Automatic Speech Recognition with Cyberon library `, +please consult the :ref:`Programming Guide ` which contains setup information for these applications. diff --git a/doc/shared/introduction.rst b/doc/shared/introduction.rst index 7b1f7aa08..5f2008a88 100644 --- a/doc/shared/introduction.rst +++ b/doc/shared/introduction.rst @@ -1,19 +1,19 @@ ################### -Product Description +Product Description ################### The XCORE-VOICE Solution consists of example designs and a C-based SDK for the development of audio front-end applications to support far-field voice use cases on the xcore.ai family of chips (XU316). The XCORE-VOICE examples are currently based on FreeRTOS or bare-metal, leveraging the flexibility of the xcore.ai platform and providing designers with a familiar environment to customize and develop products. -XCORE-VOICE example designs include turn-key solutions to enable easier product development for smart home applications such as light switches, thermostats, and home appliances. xcore.ai’s unique architecture providing powerful signal processing and accelerated AI capabilities combined with the XCORE-VOICE framework allows designers to incorporate keyword, event detection, or advanced local dictionary support to create a complete voice interface solution. Bridging designs including PDM microphone to host aggregation are also included showcasing the use of xcore.ai as an interfacing and bridging solution for deployment in existing systems. +XCORE-VOICE example designs include turn-key solutions to enable easier product development for smart home applications such as light switches, thermostats, and home appliances. xcore.ai’s unique architecture providing powerful signal processing and accelerated AI capabilities combined with the XCORE-VOICE framework allows designers to incorporate keyword, event detection, or advanced local dictionary support to create a complete voice interface solution. Bridging designs including PDM microphone to host aggregation are also included showcasing the use of xcore.ai as an interfacing and bridging solution for deployment in existing systems. The C SDK is composed of the following components: -- Peripheral IO libraries including; UART, I2C, I2S, SPI, QSPI, PDM microphones, and USB. These libraries support bare-metal and RTOS application development. +- Peripheral IO libraries including; UART, |I2C|, |I2S|, SPI, QSPI, PDM microphones, and USB. These libraries support bare-metal and RTOS application development. - Libraries core to DSP applications, including vectorized math and voice processing DSP. These libraries support bare-metal and RTOS application development. - Libraries for speech recognition applications. These libraries support bare-metal and RTOS application development. - Libraries that enable multi-core FreeRTOS development on xcore including a wide array of RTOS drivers and middleware. -- Pre-build and validated audio processing pipelines. +- Pre-build and validated audio processing pipelines. - Code Examples - Examples showing a variety of xcore features based on bare-metal and FreeRTOS programming. - Documentation - Tutorials, references and API guides. @@ -23,43 +23,43 @@ The C SDK is composed of the following components: :alt: component diagram ############ -Key Features +Key Features ############ The XCORE-VOICE Solution takes advantage of the flexible software-defined xcore-ai architecture to support numerous far-field voice use cases through the available example designs and the ability to construct user-defined audio pipeline from the SW components and libraries in the C-based SDK. -These include: +These include: **Voice Processing components** -- Two PDM microphone interfaces -- Digital signal processing pipeline -- Full duplex, stereo, Acoustic Echo Cancellation (AEC) -- Reference audio via |I2S| with automatic bulk delay insertion -- Point noise suppression via interference canceller -- Switchable stationary noise suppressor -- Programmable Automatic Gain Control (AGC) -- Flexible audio output routing and filtering +- Two PDM microphone interfaces +- Digital signal processing pipeline +- Full duplex, stereo, Acoustic Echo Cancellation (AEC) +- Reference audio via |I2S| with automatic bulk delay insertion +- Point noise suppression via interference canceller +- Switchable stationary noise suppressor +- Programmable Automatic Gain Control (AGC) +- Flexible audio output routing and filtering - Support for Sensory, Cyberon or other 3rd party Automatic Speech Recognition (ASR) software **Device Interface components** -- Full speed USB2.0 compliant device supporting USB Audio Class (UAC) 2.0 -- Flexible Peripheral Interfaces -- Programmable digital general-purpose inputs and outputs +- Full speed USB2.0 compliant device supporting USB Audio Class (UAC) 2.0 +- Flexible Peripheral Interfaces +- Programmable digital general-purpose inputs and outputs **Example Designs utilizing above components** -- Far-Field Voice Local Command -- Low Power Far-Field Voice Local Command -- Far-Field Voice Assistance +- Far-Field Voice Local Command +- Low Power Far-Field Voice Local Command +- Far-Field Voice Assistance **Firmware Management** -- Boot from QSPI Flash -- Default firmware image for power-on operation -- Option to boot from a local host processor via SPI -- Device Firmware Update (DFU) via USB or other transport +- Boot from QSPI Flash +- Default firmware image for power-on operation +- Option to boot from a local host processor via SPI +- Device Firmware Update (DFU) via USB or |I2C| **Power Consumption** @@ -70,13 +70,13 @@ These include: Obtaining the Hardware ###################### -The XK-VOICE-L71 DevKit and Hardware Manual can be obtained from the |HARDWARE_URL| product information page. +The XK-VOICE-L71 DevKit and Hardware Manual can be obtained from the |HARDWARE_URL| product information page. -The XK-VOICE-L71 is based on the: `XU316-1024-QF60A `_ +The XK-VOICE-L71 is based on the: `XU316-1024-QF60A `_ -The XCORE-AI-EXPLORER DevKit and Hardware Manual used in the :ref:`Microphone Aggregation ` example can be obtained from the |HARDWARE_URL| product information page. +The XCORE-AI-EXPLORER DevKit and Hardware Manual used in the :ref:`Microphone Aggregation ` example can be obtained from the |HARDWARE_URL| product information page. -Learn more about the `The XMOS XS3 Architecture `_ +Learn more about the `The XMOS XS3 Architecture `_ ###################### Obtaining the Software @@ -86,23 +86,23 @@ Obtaining the Software Development Tools ***************** -It is recommended that you download and install the latest release of the `XTC Tools `__. XTC Tools 15.2.1 or newer are required. If you already have the XTC Toolchain installed, you can check the version with the following command: +It is recommended that you download and install the latest release of the `XTC Tools `__. XTC Tools |TOOLS_VERSION| or newer are required. If you already have the XTC Toolchain installed, you can check the version with the following command: .. code-block:: console xcc --version ************************** -Application Demonstrations +Application Demonstrations ************************** -If you only want to run the example designs, pre-built firmware and other software can be downloaded from the |SOFTWARE_URL| product information page. +If you only want to run the example designs, pre-built firmware and other software can be downloaded from the |SOFTWARE_URL| product information page. *********** Source Code *********** -If you wish to modify the example designs, a zip archive of all source code can be downloaded from the |SOFTWARE_URL| product information page. +If you wish to modify the example designs, a zip archive of all source code can be downloaded from the |SOFTWARE_URL| product information page. See the :ref:`Programming Guide ` for information on: @@ -113,11 +113,11 @@ See the :ref:`Programming Guide ` for information o Cloning the Repository ====================== -Alternatively, the source code can be obtained by cloning the public GitHub repository. +Alternatively, the source code can be obtained by cloning the public GitHub repository. .. note:: - Cloning requires a `GitHub `_ account configured with `SSH key authentication `_. + Cloning requires a `GitHub `_ account configured with `SSH key authentication `_. Run the following `git` command to clone the repository and all submodules: diff --git a/doc/substitutions.inc b/doc/substitutions.inc index 8aa28a317..ecd748007 100644 --- a/doc/substitutions.inc +++ b/doc/substitutions.inc @@ -1,6 +1,3 @@ -.. |HARDWARE_URL| replace:: `XK-VOICE-L71 `__ -.. |SOFTWARE_URL| replace:: `XCORE-VOICE `__ - -.. |newpage| raw:: latex - - \clearpage +.. |HARDWARE_URL| replace:: `XK-VOICE-L71 `__ +.. |SOFTWARE_URL| replace:: `XCORE-VOICE `__ +.. |TOOLS_VERSION| replace:: 15.3.0 diff --git a/examples/asrc_demo/README.rst b/examples/asrc_demo/README.rst index d2e3f7c86..4fe066fbd 100644 --- a/examples/asrc_demo/README.rst +++ b/examples/asrc_demo/README.rst @@ -2,11 +2,21 @@ ASRC Demo Application ********************* +.. warning:: + + This example is based on the RTOS framework and drivers, and it can lead to latency of up to 20 ms in the system. + More information can be found in the Overview section of the ASRC example in the Programming Guide. + + For a proposed implementation with lower latency, please refer to the bare-metal examples below: + + - `AN02003: SPDIF/ADAT/I2S Slave Receive to I2S Slave Bridge with ASRC `__ + + This is the XCORE-VOICE Asynchronous Sampling Rate Converter (ASRC) example design. The example system implements a stereo I2S slave and a stereo adaptive UAC2.0 interface and exchanges data between the two interfaces. Since the two interfaces are operating in different clock domains, there is an ASRC block between them that converts from the input to the output sampling rate. -There are two ASRC blocks, one in the I2S → ASRC → USB path and the other in the USB → ASRC → I2S path. +There are two ASRC blocks, one in the I2S -> ASRC -> USB path and the other in the USB -> ASRC -> I2S path. The application also monitors and computes the instantaneous ratio between the ASRC input and output sampling rate. The rate ratio is used by the ASRC task to dynamically adapt filter coefficients using spline interpolation in its filtering stage. @@ -15,7 +25,7 @@ The I2S slave interface is a stereo 32 bit interface supporting sampling rates b The USB interface is a stereo, 32 bit, 48 kHz, High-Speed, USB Audio Class 2, Adaptive interface. -The ASRC algorithm in the `lib_src `_ library is used for the ASRC processing. The ASRC processing is block based and works on a block size of 244 samples per channel in the I2S → ASRC → USB path and 96 samples per channel in the USB → ASRC → I2S path. +The ASRC algorithm in the `lib_src `_ library is used for the ASRC processing. The ASRC processing is block based and works on a block size of 244 samples per channel in the I2S -> ASRC -> USB path and 96 samples per channel in the USB -> ASRC -> I2S path. Supported Hardware ================== @@ -58,25 +68,15 @@ Download the main repo and submodules using: Building the app ================ -First install and source the XTC version: 15.2.1 tools. The output should be -something like this: - -:: - - $ xcc --version - xcc: Build 19-198606c, Oct-25-2022 - XTC version: 15.2.1 - Copyright (C) XMOS Limited 2008-2021. All Rights Reserved. - +First make sure that your XTC tools environment is activated. Linux or Mac ------------ -To build for the first time, run ``cmake`` to create the -make files: +After having your python environment activated, run the following commands in the root folder to build the firmware: :: - + $ pip install -r requirements.txt $ mkdir build $ cd build $ cmake --toolchain ../xmos_cmake_toolchain/xs3a.cmake .. @@ -93,10 +93,9 @@ Following initial ``cmake`` build, for subsequent builds, as long as new source Windows ------- -It is highly recommended to use ``Ninja`` as the make system under -``cmake``. Not only is it a lot faster than MSVC ``nmake``, it also -works around an issue where certain path names may cause an issue with -the XMOS compiler under Windows. +It is recommended to use `Ninja` or `xmake` as the make system under Windows. +`Ninja` has been observed to be faster than `xmake`, however `xmake` comes natively with XTC tools. +This firmware has been tested with `Ninja` version v1.11.1. To install Ninja, follow these steps: @@ -109,11 +108,11 @@ To install Ninja, follow these steps: set the path in the current command line session using something like ``set PATH=%PATH%;C:\Users\xmos\utils\ninja`` -To build for the first time, run ``cmake`` to create the -make files: +After having your python environment activated, run the following commands in the root folder to build the firmware: :: + $ pip install -r requirements.txt $ md build $ cd build $ cmake -G "Ninja" --toolchain ..\xmos_cmake_toolchain\xs3a.cmake .. diff --git a/examples/asrc_demo/bsp_config/XK_VOICE_L71/platform/platform_init.c b/examples/asrc_demo/bsp_config/XK_VOICE_L71/platform/platform_init.c index fb330f222..d701bd549 100644 --- a/examples/asrc_demo/bsp_config/XK_VOICE_L71/platform/platform_init.c +++ b/examples/asrc_demo/bsp_config/XK_VOICE_L71/platform/platform_init.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* System headers */ @@ -114,6 +114,7 @@ static void usb_init(void) void platform_init(chanend_t other_tile_c) { rtos_intertile_init(intertile_ctx, other_tile_c); + rtos_intertile_init(intertile_usb_audio_ctx, other_tile_c); rtos_intertile_init(intertile_i2s_audio_ctx, other_tile_c); diff --git a/examples/asrc_demo/src/usb/usb_dfu.c b/examples/asrc_demo/src/usb/usb_dfu.c index b9c140aae..89f621fcc 100644 --- a/examples/asrc_demo/src/usb/usb_dfu.c +++ b/examples/asrc_demo/src/usb/usb_dfu.c @@ -80,14 +80,14 @@ void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const* data, u if (dn_base_addr == 0) { total_len = 0; dn_base_addr = rtos_dfu_image_get_upgrade_addr(dfu_image_ctx); - bytes_avail = data_partition_base_addr - dn_base_addr; + bytes_avail = data_partition_base_addr - dn_base_addr; } /* fallthrough */ case 2: if (dn_base_addr == 0) { total_len = 0; dn_base_addr = data_partition_base_addr; - bytes_avail = rtos_qspi_flash_size_get(qspi_flash_ctx) - dn_base_addr; + bytes_avail = rtos_qspi_flash_size_get(qspi_flash_ctx) - dn_base_addr; } rtos_printf("Using addr 0x%x\nsize %u\n", dn_base_addr, bytes_avail); if(length > 0) { diff --git a/examples/examples.cmake b/examples/examples.cmake index 413503ca9..517a507e4 100644 --- a/examples/examples.cmake +++ b/examples/examples.cmake @@ -6,6 +6,8 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL XCORE_XS3A) include(${CMAKE_CURRENT_LIST_DIR}/asrc_demo/asrc_demo.cmake) include(${CMAKE_CURRENT_LIST_DIR}/ffd/ffd_sensory.cmake) include(${CMAKE_CURRENT_LIST_DIR}/ffd/ffd_cyberon.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/ffd/ffd_i2s_input_cyberon.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/low_power_ffd/low_power_ffd_sensory.cmake) include(${CMAKE_CURRENT_LIST_DIR}/mic_aggregator/mic_aggregator.cmake) else() diff --git a/examples/ffd/README.rst b/examples/ffd/README.rst index e1e27b0cc..9d5fe4c43 100644 --- a/examples/ffd/README.rst +++ b/examples/ffd/README.rst @@ -2,7 +2,7 @@ Far-field Voice Local Command ***************************** -This is the XCORE-VOICE far-field voice local control firmware. Two examples are provided: one example uses the Sensory TrulyHandsfree™ (THF) speech recognition, and the other one uses the Cyberon DSPotter™ speech recognition. +This is the XCORE-VOICE far-field voice local control firmware. Three examples are provided: all examples include speech recognition and a local dictionary. One example uses the Sensory TrulyHandsfree™ (THF) libraries, and the other ones use the Cyberon DSPotter™ libraries. The two examples with the Cyberon DSPotter™ libraries differ in the audio source fed into the intent engine. One example uses the audio source from the microphone array, and the other uses the audio source from the I2S interface. This software is an evaluation version only. It includes a mechanism that limits the maximum number of recognitions. You can reset the counter to 0 by restarting or rebooting the application. @@ -48,21 +48,11 @@ Supported Hardware and pre-requisites This example is supported on the XK_VOICE_L71 board. -On the host machine the XTC tools, version 15.2.1, must be installed and sourced. -The output should be -something like this: +Make sure that your XTC tools environment is activated. -:: - - $ xcc --version - xcc: Build 19-198606c, Oct-25-2022 - XTC version: 15.2.1 - Copyright (C) XMOS Limited 2008-2021. All Rights Reserved. - -On Windows it is highly recommended to use ``Ninja`` as the make system under -``cmake``. Not only is it a lot faster than MSVC ``nmake``, it also -works around an issue where certain path names may cause an issue with -the XMOS compiler under Windows. +It is recommended to use `Ninja` or `xmake` as the make system under Windows. +`Ninja` has been observed to be faster than `xmake`, however `xmake` comes natively with XTC tools. +This firmware has been tested with `Ninja` version v1.11.1. To install Ninja, follow these steps: @@ -88,6 +78,11 @@ This application requires a host application to create the flash data partition. In the commands below ```` can be either ``sensory`` or ``cyberon``, depending on the choice of the speech recognition engine and model. +.. note:: + + The Cyberon speech recognition engine is integrated in two examples. The ``example_ffd_cyberon`` use the microphone array as the audio source, and the ``example_ffd_i2s_input_cyberon`` uses the I2S interface as the audio source. + In the rest of this file, we use only the ``example_ffd_`` as an example. + .. note:: Permissions may be required to install the host applications. @@ -115,12 +110,13 @@ The host applications will be installed at ``%USERPROFILE%\.xmos\bin``, and may Building the Firmware ===================== -Run the following commands in the root folder to build the firmware: +After having your python environment activated, run the following commands in the root folder to build the firmware: On Linux and Mac run: :: + pip install -r requirements.txt cmake -B build --toolchain xmos_cmake_toolchain/xs3a.cmake cd build make example_ffd_ @@ -129,6 +125,7 @@ On Windows run: :: + pip install -r requirements.txt cmake -G Ninja -B build --toolchain xmos_cmake_toolchain/xs3a.cmake cd build ninja example_ffd_ diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn b/examples/ffd/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn index b927e064e..5427e8df3 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn +++ b/examples/ffd/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn @@ -56,6 +56,10 @@ + + + + @@ -77,12 +81,10 @@ - + - - diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.c b/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.c index e7fae7bee..49c86aafd 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.c +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.c @@ -27,5 +27,13 @@ rtos_i2c_master_t *i2c_master_ctx = &i2c_master_ctx_s; static rtos_i2s_t i2s_ctx_s; rtos_i2s_t *i2s_ctx = &i2s_ctx_s; +static rtos_i2c_slave_t i2c_slave_ctx_s; +rtos_i2c_slave_t *i2c_slave_ctx = &i2c_slave_ctx_s; + static rtos_uart_tx_t uart_tx_ctx_s; rtos_uart_tx_t *uart_tx_ctx = &uart_tx_ctx_s; + +#if appconfRECOVER_MCLK_I2S_APP_PLL +static sw_pll_ctx_t sw_pll_ctx_s; +sw_pll_ctx_t *sw_pll_ctx = &sw_pll_ctx_s; +#endif diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.h b/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.h index 496dbfa15..ebfb3180f 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.h +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/driver_instances.h @@ -12,6 +12,7 @@ extern "C" { #include "rtos_qspi_flash.h" #include "rtos_gpio.h" #include "rtos_i2c_master.h" +#include "rtos_i2c_slave.h" #include "rtos_i2s.h" #include "rtos_uart_tx.h" @@ -21,9 +22,17 @@ extern "C" { #include "rtos_mic_array.h" +#if appconfRECOVER_MCLK_I2S_APP_PLL +/* Config headers for sw_pll */ +#include "sw_pll.h" +#include "fractions_1000ppm.h" +#include "register_setup_1000ppm.h" +#endif + /* Tile specifiers */ #define FLASH_TILE_NO 0 #define I2C_TILE_NO 0 +#define I2C_CTRL_TILE_NO I2C_TILE_NO #define MICARRAY_TILE_NO 1 #define I2S_TILE_NO 1 #define UART_TILE_NO 0 @@ -52,7 +61,21 @@ extern rtos_gpio_t *gpio_ctx_t0; extern rtos_gpio_t *gpio_ctx_t1; extern rtos_mic_array_t *mic_array_ctx; extern rtos_i2c_master_t *i2c_master_ctx; +extern rtos_i2c_slave_t *i2c_slave_ctx; extern rtos_i2s_t *i2s_ctx; extern rtos_uart_tx_t *uart_tx_ctx; +#if appconfRECOVER_MCLK_I2S_APP_PLL +typedef struct { + port_t p_mclk_count; // Used for keeping track of MCLK output for sw_pll + port_t p_bclk_count; // Used for keeping track of BCLK input for sw_pll + sw_pll_state_t *sw_pll; // Pointer to sw_pll state (if used) + +}sw_pll_ctx_t; + +static sw_pll_state_t sw_pll = {0}; + +extern sw_pll_ctx_t *sw_pll_ctx; +#endif + #endif /* DRIVER_INSTANCES_H_ */ diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_conf.h b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_conf.h index 23d382de1..40d68c242 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_conf.h +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_conf.h @@ -54,6 +54,14 @@ #define appconfI2S_IO_CORE 2 /* Must be kept off core 0 with the RTOS tick ISR */ #endif /* appconfI2S_IO_CORE */ +#ifndef appconfI2C_IO_CORE +#define appconfI2C_IO_CORE 3 /* Must be kept off core 0 with the RTOS tick ISR */ +#endif /* appconfI2C_IO_CORE */ + +#ifndef appconfI2C_INTERRUPT_CORE +#define appconfI2C_INTERRUPT_CORE 0 /* Must be kept off I/O cores. */ +#endif /* appconfI2C_INTERRUPT_CORE */ + #ifndef appconfPDM_MIC_INTERRUPT_CORE #define appconfPDM_MIC_INTERRUPT_CORE 3 /* Must be kept off I/O cores. Best kept off core 0 with the tick ISR. */ #endif /* appconfPDM_MIC_INTERRUPT_CORE */ @@ -81,7 +89,11 @@ /* I/O Task Priorities */ /*****************************************/ #ifndef appconfQSPI_FLASH_TASK_PRIORITY -#define appconfQSPI_FLASH_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define appconfQSPI_FLASH_TASK_PRIORITY (configMAX_PRIORITIES-1) #endif /* appconfQSPI_FLASH_TASK_PRIORITY */ +#ifndef appconfI2C_TASK_PRIORITY +#define appconfI2C_TASK_PRIORITY (configMAX_PRIORITIES/2) +#endif /* appconfI2C_TASK_PRIORITY */ + #endif /* PLATFORM_CONF_H_ */ diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_init.c b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_init.c index af3e77fd0..f2df67802 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_init.c +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_init.c @@ -12,7 +12,7 @@ static void mclk_init(chanend_t other_tile_c) { -#if ON_TILE(1) +#if ON_TILE(I2S_TILE_NO) app_pll_init(); #endif } @@ -54,7 +54,7 @@ static void gpio_init(void) intertile_ctx); #endif -#if ON_TILE(1) +#if ON_TILE(I2S_TILE_NO) rtos_gpio_init(gpio_ctx_t1); rtos_gpio_rpc_client_init( @@ -72,6 +72,15 @@ static void gpio_init(void) static void i2c_init(void) { +#if appconfINTENT_I2C_SLAVE_POLLED_ENABLED && ON_TILE(I2C_TILE_NO) + rtos_i2c_slave_init(i2c_slave_ctx, + (1 << appconfI2C_IO_CORE), + PORT_I2C_SCL, + PORT_I2C_SDA, + appconfI2C_SLAVE_DEVICE_ADDR); +#endif + +#if appconfI2C_MASTER_DAC_ENABLED || appconfINTENT_I2C_MASTER_OUTPUT_ENABLED static rtos_driver_rpc_t i2c_rpc_config; #if ON_TILE(I2C_TILE_NO) @@ -94,6 +103,66 @@ static void i2c_init(void) &i2c_rpc_config, intertile_ctx); #endif +#endif +} + +#if ON_TILE(I2S_TILE_NO) && appconfRECOVER_MCLK_I2S_APP_PLL +static int *p_lock_status = NULL; +/// @brief Save the pointer to the pll lock_status variable +static void set_pll_lock_status_ptr(int* p) +{ + p_lock_status = p; +} +#endif + +static void platform_sw_pll_init(void) +{ +#if ON_TILE(I2S_TILE_NO) && appconfRECOVER_MCLK_I2S_APP_PLL + + port_t p_bclk = PORT_I2S_BCLK; + port_t p_mclk = PORT_MCLK; + port_t p_mclk_count = PORT_MCLK_COUNT; // Used internally by sw_pll + port_t p_bclk_count = PORT_BCLK_COUNT; // Used internally by sw_pll + xclock_t ck_bclk = I2S_CLKBLK; + + port_enable(p_mclk); + port_enable(p_bclk); + // NOTE: p_lrclk does not need to be enabled by the caller + + set_pll_lock_status_ptr(&sw_pll.lock_status); + // Create clock from mclk port and use it to clock the p_mclk_count port which will count MCLKs. + port_enable(p_mclk_count); + port_enable(p_bclk_count); + + // Allow p_mclk_count to count mclks + xclock_t clk_mclk = MCLK_CLKBLK; + clock_enable(clk_mclk); + clock_set_source_port(clk_mclk, p_mclk); + port_set_clock(p_mclk_count, clk_mclk); + clock_start(clk_mclk); + + // Allow p_bclk_count to count bclks + port_set_clock(p_bclk_count, ck_bclk); + sw_pll_lut_init(&sw_pll, + SW_PLL_15Q16(0.0), + SW_PLL_15Q16(1.0), + SW_PLL_15Q16(0.0), + PLL_CONTROL_LOOP_COUNT_INT, + PLL_RATIO, + (appconfBCLK_NOMINAL_HZ / appconfLRCLK_NOMINAL_HZ), + frac_values_90, + SW_PLL_NUM_LUT_ENTRIES(frac_values_90), + APP_PLL_CTL_REG, + APP_PLL_DIV_REG, + SW_PLL_NUM_LUT_ENTRIES(frac_values_90) / 2, + PLL_PPM_RANGE); + + debug_printf("Using SW PLL to track I2S input\n"); + sw_pll_ctx->sw_pll = &sw_pll; + sw_pll_ctx->p_mclk_count = p_mclk_count; + sw_pll_ctx->p_bclk_count = p_bclk_count; + +#endif } static void mics_init(void) @@ -109,8 +178,11 @@ static void mics_init(void) static void i2s_init(void) { #if appconfI2S_ENABLED +#if appconfI2S_MODE == appconfI2S_MODE_MASTER static rtos_driver_rpc_t i2s_rpc_config; +#endif #if ON_TILE(I2S_TILE_NO) +#if appconfI2S_MODE == appconfI2S_MODE_MASTER rtos_intertile_t *client_intertile_ctx[1] = {intertile_ctx}; port_t p_i2s_dout[1] = { PORT_I2S_DAC_DATA @@ -137,13 +209,35 @@ static void i2s_init(void) &i2s_rpc_config, client_intertile_ctx, 1); +#elif appconfI2S_MODE == appconfI2S_MODE_SLAVE + port_t p_i2s_dout[1] = { + PORT_I2S_ADC_DATA + }; + port_t p_i2s_din[1] = { + PORT_I2S_DAC_DATA + }; + rtos_i2s_slave_init( + i2s_ctx, + (1 << appconfI2S_IO_CORE), + p_i2s_dout, + 1, + p_i2s_din, + 1, + PORT_I2S_BCLK, + PORT_I2S_LRCLK, + I2S_CLKBLK); +#else + #error "Invalid I2S mode" +#endif #else +#if appconfI2S_MODE == appconfI2S_MODE_MASTER rtos_i2s_rpc_client_init( i2s_ctx, &i2s_rpc_config, intertile_ctx); #endif #endif +#endif } static void uart_init(void) @@ -166,7 +260,7 @@ void platform_init(chanend_t other_tile_c) { rtos_intertile_init(intertile_ctx, other_tile_c); rtos_intertile_init(intertile_ap_ctx, other_tile_c); - + platform_sw_pll_init(); mclk_init(other_tile_c); gpio_init(); flash_init(); diff --git a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_start.c b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_start.c index 476003de2..d30445aa0 100644 --- a/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_start.c +++ b/examples/ffd/bsp_config/XK_VOICE_L71/platform/platform_start.c @@ -14,6 +14,9 @@ #include "platform_conf.h" #include "platform/driver_instances.h" #include "dac3101.h" +#include "i2c_reg_handling.h" + +extern asr_result_t last_asr_result; extern void i2s_rate_conversion_enable(void); @@ -39,16 +42,34 @@ static void flash_start(void) static void i2c_master_start(void) { +#if appconfI2C_MASTER_DAC_ENABLED || appconfINTENT_I2C_MASTER_OUTPUT_ENABLED rtos_i2c_master_rpc_config(i2c_master_ctx, appconfI2C_MASTER_RPC_PORT, appconfI2C_MASTER_RPC_PRIORITY); #if ON_TILE(I2C_TILE_NO) rtos_i2c_master_start(i2c_master_ctx); #endif +#endif +} + +static void i2c_slave_start(void) +{ +#if appconfINTENT_I2C_SLAVE_POLLED_ENABLED && ON_TILE(I2C_TILE_NO) + rtos_i2c_slave_start(i2c_slave_ctx, + &last_asr_result, + (rtos_i2c_slave_start_cb_t) NULL, + (rtos_i2c_slave_rx_cb_t) write_device_reg, + (rtos_i2c_slave_tx_start_cb_t) read_device_reg, + (rtos_i2c_slave_tx_done_cb_t) NULL, + NULL, + NULL, + appconfI2C_INTERRUPT_CORE, + appconfI2C_TASK_PRIORITY); +#endif } static void audio_codec_start(void) { -#if appconfI2S_ENABLED +#if appconfI2S_ENABLED && appconfI2C_MASTER_DAC_ENABLED int ret = 0; #if ON_TILE(I2C_TILE_NO) if (dac3101_init(appconfI2S_AUDIO_SAMPLE_RATE) != 0) { @@ -75,7 +96,9 @@ static void mics_start(void) static void i2s_start(void) { #if appconfI2S_ENABLED +#if appconfI2S_MODE == appconfI2S_MODE_MASTER rtos_i2s_rpc_config(i2s_ctx, appconfI2S_RPC_PORT, appconfI2S_RPC_PRIORITY); +#endif #if ON_TILE(I2S_TILE_NO) if (appconfI2S_AUDIO_SAMPLE_RATE == 3*appconfAUDIO_PIPELINE_SAMPLE_RATE) { @@ -112,4 +135,6 @@ void platform_start(void) mics_start(); i2s_start(); uart_start(); + // I2C slave can be started only after i2c_master_start() is completed + i2c_slave_start(); } diff --git a/examples/ffd/ffd_cyberon.cmake b/examples/ffd/ffd_cyberon.cmake index 1cf7db3bf..355e96576 100644 --- a/examples/ffd/ffd_cyberon.cmake +++ b/examples/ffd/ffd_cyberon.cmake @@ -13,8 +13,6 @@ set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src ${CMAKE_CURRENT_LIST_DIR}/src/gpio_ctrl ${CMAKE_CURRENT_LIST_DIR}/src/intent_engine - ${CMAKE_CURRENT_LIST_DIR}/src/intent_handler - ${CMAKE_CURRENT_LIST_DIR}/src/intent_handler/audio_response ${CMAKE_CURRENT_LIST_DIR}/src/power ) set(RTOS_CONF_INCLUDES @@ -88,7 +86,13 @@ set(APP_LINK_OPTIONS set(APP_COMMON_LINK_LIBRARIES sln_voice::app::ffd::ap sln_voice::app::asr::Cyberon + sln_voice::app::asr::device_memory + sln_voice::app::asr::gpio_ctrl + sln_voice::app::asr::intent_engine + sln_voice::app::asr::intent_handler sln_voice::app::ffd::xk_voice_l71 + lib_src + lib_sw_pll ) #********************** diff --git a/examples/ffd/ffd_i2s_input_cyberon.cmake b/examples/ffd/ffd_i2s_input_cyberon.cmake new file mode 100644 index 000000000..c5ebfa089 --- /dev/null +++ b/examples/ffd/ffd_i2s_input_cyberon.cmake @@ -0,0 +1,211 @@ +set(FFD_SRC_ROOT ${CMAKE_CURRENT_LIST_DIR}) + +set(MODEL_LANGUAGE "english_usa") +set(CYBERON_COMMAND_NET_FILE "${FFD_SRC_ROOT}/model/english_usa/Hello_XMOS_pack_WithTxt.bin.Enc.NibbleSwap") + +#********************** +# Gather Sources +#********************** +file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c ) + + +set(APP_INCLUDES + ${CMAKE_CURRENT_LIST_DIR}/src + ${CMAKE_CURRENT_LIST_DIR}/src/control + ${CMAKE_CURRENT_LIST_DIR}/src/gpio_ctrl + ${CMAKE_CURRENT_LIST_DIR}/src/intent_engine + ${CMAKE_CURRENT_LIST_DIR}/src/power +) +set(RTOS_CONF_INCLUDES + ${CMAKE_CURRENT_LIST_DIR}/src/rtos_conf +) + +#********************** +# QSPI Flash Layout +#********************** +set(BOOT_PARTITION_SIZE 0x100000) +set(FILESYSTEM_SIZE_KB 1024) +math(EXPR FILESYSTEM_SIZE_BYTES + "1024 * ${FILESYSTEM_SIZE_KB}" + OUTPUT_FORMAT HEXADECIMAL +) + +set(CALIBRATION_PATTERN_START_ADDRESS ${BOOT_PARTITION_SIZE}) + +math(EXPR FILESYSTEM_START_ADDRESS + "${CALIBRATION_PATTERN_START_ADDRESS} + ${LIB_QSPI_FAST_READ_DEFAULT_CAL_SIZE_BYTES}" + OUTPUT_FORMAT HEXADECIMAL +) + +math(EXPR MODEL_START_ADDRESS + "${FILESYSTEM_START_ADDRESS} + ${FILESYSTEM_SIZE_BYTES}" + OUTPUT_FORMAT HEXADECIMAL +) + +set(CALIBRATION_PATTERN_DATA_PARTITION_OFFSET 0) + +math(EXPR FILESYSTEM_DATA_PARTITION_OFFSET + "${CALIBRATION_PATTERN_DATA_PARTITION_OFFSET} + ${LIB_QSPI_FAST_READ_DEFAULT_CAL_SIZE_BYTES}" + OUTPUT_FORMAT DECIMAL +) + +math(EXPR MODEL_DATA_PARTITION_OFFSET + "${FILESYSTEM_DATA_PARTITION_OFFSET} + ${FILESYSTEM_SIZE_BYTES}" + OUTPUT_FORMAT DECIMAL +) + + +#********************** +# Flags +#********************** +set(APP_COMPILER_FLAGS + -Os + -g + -report + -fxscope + -mcmodel=large + -Wno-xcore-fptrgroup + ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope +) + +set(APP_COMPILE_DEFINITIONS + configENABLE_DEBUG_PRINTF=1 + PLATFORM_USES_TILE_0=1 + PLATFORM_USES_TILE_1=1 + QSPI_FLASH_FILESYSTEM_START_ADDRESS=${FILESYSTEM_START_ADDRESS} + QSPI_FLASH_MODEL_START_ADDRESS=${MODEL_START_ADDRESS} + QSPI_FLASH_CALIBRATION_ADDRESS=${CALIBRATION_PATTERN_START_ADDRESS} + ASR_CYBERON=1 + appconfUSE_I2S_INPUT=1 + appconfAUDIO_PLAYBACK_ENABLED=1 + appconfI2S_MODE=appconfI2S_MODE_SLAVE + appconfI2S_AUDIO_SAMPLE_RATE=48000 + appconfINTENT_I2C_SLAVE_POLLED_ENABLED=1 + appconfINTENT_I2C_MASTER_OUTPUT_ENABLED=0 + appconfI2C_MASTER_DAC_ENABLED=0 + appconfRECOVER_MCLK_I2S_APP_PLL=1 + appconfINTENT_UART_DEBUG_INFO_ENABLED=1 + appconfAUDIO_PIPELINE_SKIP_IC_AND_VNR=1 + appconfAUDIO_PIPELINE_SKIP_NS=1 + appconfAUDIO_PIPELINE_SKIP_AGC=1 +) + +set(APP_LINK_OPTIONS + -report + -lotp3 + ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope +) + +set(APP_COMMON_LINK_LIBRARIES + sln_voice::app::ffd::ap + sln_voice::app::asr::Cyberon + sln_voice::app::asr::device_memory + sln_voice::app::asr::gpio_ctrl + sln_voice::app::asr::intent_engine + sln_voice::app::asr::intent_handler + sln_voice::app::ffd::xk_voice_l71 + lib_src + lib_sw_pll +) + +#********************** +# Tile Targets +#********************** +set(TARGET_NAME tile0_example_ffd_i2s_input_cyberon) +add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL) +target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES}) +target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES} ${RTOS_CONF_INCLUDES}) +target_compile_definitions(${TARGET_NAME} PUBLIC ${APP_COMPILE_DEFINITIONS} THIS_XCORE_TILE=0) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_COMMON_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +set(TARGET_NAME tile1_example_ffd_i2s_input_cyberon) +add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL) +target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES}) +target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES} ${RTOS_CONF_INCLUDES}) +target_compile_definitions(${TARGET_NAME} PUBLIC ${APP_COMPILE_DEFINITIONS} THIS_XCORE_TILE=1) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_COMMON_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS} ) +unset(TARGET_NAME) + +#********************** +# Merge binaries +#********************** +merge_binaries(example_ffd_i2s_input_cyberon tile0_example_ffd_i2s_input_cyberon tile1_example_ffd_i2s_input_cyberon 1) + +#********************** +# Create run and debug targets +#********************** +create_run_target(example_ffd_i2s_input_cyberon) +create_debug_target(example_ffd_i2s_input_cyberon) + +#********************** +# Create data partition support targets +#********************** +set(TARGET_NAME example_ffd_i2s_input_cyberon) +set(DATA_PARTITION_FILE ${TARGET_NAME}_data_partition.bin) +set(MODEL_FILE ${TARGET_NAME}_model.bin) +set(FATFS_FILE ${TARGET_NAME}_fat.fs) +set(FLASH_CAL_FILE ${LIB_QSPI_FAST_READ_ROOT_PATH}/lib_qspi_fast_read/calibration_pattern_nibble_swap.bin) + +add_custom_target(${MODEL_FILE} ALL + COMMAND ${CMAKE_COMMAND} -E copy ${CYBERON_COMMAND_NET_FILE} ${MODEL_FILE} + COMMENT + "Copy Cyberon NET file" + VERBATIM +) + +create_filesystem_target( + #[[ Target ]] ${TARGET_NAME} + #[[ Input Directory ]] ${CMAKE_CURRENT_LIST_DIR}/filesystem_support/${MODEL_LANGUAGE} + #[[ Image Size ]] ${FILESYSTEM_SIZE_BYTES} +) + +add_custom_command( + OUTPUT ${DATA_PARTITION_FILE} + COMMAND ${CMAKE_COMMAND} -E rm -f ${DATA_PARTITION_FILE} + COMMAND datapartition_mkimage -v -b 1 + -i ${FLASH_CAL_FILE}:${CALIBRATION_PATTERN_DATA_PARTITION_OFFSET} ${FATFS_FILE}:${FILESYSTEM_DATA_PARTITION_OFFSET} ${MODEL_FILE}:${MODEL_DATA_PARTITION_OFFSET} + -o ${DATA_PARTITION_FILE} + DEPENDS + ${MODEL_FILE} + make_fs_${TARGET_NAME} + ${FLASH_CAL_FILE} + COMMENT + "Create data partition" + VERBATIM +) + +set(DATA_PARTITION_FILE_LIST + ${DATA_PARTITION_FILE} + ${MODEL_FILE} + ${FATFS_FILE} + ${FLASH_CAL_FILE} +) + +set(DATA_PARTITION_DEPENDS_LIST + ${DATA_PARTITION_FILE} + ${MODEL_FILE} + make_fs_${TARGET_NAME} +) + +# The list of files to copy and the dependency list for populating +# the data partition folder are identical. +create_data_partition_directory( + #[[ Target ]] ${TARGET_NAME} + #[[ Copy Files ]] "${DATA_PARTITION_FILE_LIST}" + #[[ Dependencies ]] "${DATA_PARTITION_DEPENDS_LIST}" +) + +create_flash_app_target( + #[[ Target ]] ${TARGET_NAME} + #[[ Boot Partition Size ]] ${BOOT_PARTITION_SIZE} + #[[ Data Partition Contents ]] ${DATA_PARTITION_FILE} + #[[ Dependencies ]] ${DATA_PARTITION_FILE} +) + +unset(DATA_PARTITION_FILE_LIST) +unset(DATA_PARTITION_DEPENDS_LIST) diff --git a/examples/ffd/ffd_sensory.cmake b/examples/ffd/ffd_sensory.cmake index 4bc766908..d2ad4ac6b 100644 --- a/examples/ffd/ffd_sensory.cmake +++ b/examples/ffd/ffd_sensory.cmake @@ -25,8 +25,6 @@ set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src ${CMAKE_CURRENT_LIST_DIR}/src/gpio_ctrl ${CMAKE_CURRENT_LIST_DIR}/src/intent_engine - ${CMAKE_CURRENT_LIST_DIR}/src/intent_handler - ${CMAKE_CURRENT_LIST_DIR}/src/intent_handler/audio_response ${CMAKE_CURRENT_LIST_DIR}/src/power ) set(RTOS_CONF_INCLUDES @@ -100,7 +98,13 @@ set(APP_LINK_OPTIONS set(APP_COMMON_LINK_LIBRARIES sln_voice::app::ffd::ap sln_voice::app::asr::sensory + sln_voice::app::asr::device_memory + sln_voice::app::asr::gpio_ctrl + sln_voice::app::asr::intent_engine + sln_voice::app::asr::intent_handler sln_voice::app::ffd::xk_voice_l71 + lib_src + lib_sw_pll ) #********************** diff --git a/examples/ffd/src/app_conf.h b/examples/ffd/src/app_conf.h index d5a4ce414..1a0e9e58d 100644 --- a/examples/ffd/src/app_conf.h +++ b/examples/ffd/src/app_conf.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef APP_CONF_H_ @@ -11,12 +11,13 @@ #define appconfI2C_MASTER_RPC_PORT 4 #define appconfI2S_RPC_PORT 5 #define appconfINTENT_ENGINE_READY_SYNC_PORT 16 +#define appconfI2S_OUTPUT_SLAVE_PORT 8 /* Application tile specifiers */ #include "platform/driver_instances.h" -#define AUDIO_PIPELINE_TILE_NO MICARRAY_TILE_NO -#define ASR_TILE_NO FLASH_TILE_NO -#define FS_TILE_NO FLASH_TILE_NO +#define AUDIO_PIPELINE_OUTPUT_TILE_NO MICARRAY_TILE_NO +#define ASR_TILE_NO FLASH_TILE_NO +#define FS_TILE_NO FLASH_TILE_NO /* Audio Pipeline Configuration */ #define appconfAUDIO_CLOCK_FREQUENCY MIC_ARRAY_CONFIG_MCLK_FREQ @@ -70,24 +71,69 @@ #define appconfINTENT_TRANSPORT_DELAY_MS 50 #endif -#ifndef appconfINTENT_I2C_OUTPUT_ENABLED -#define appconfINTENT_I2C_OUTPUT_ENABLED 1 +#ifndef appconfINTENT_I2C_MASTER_OUTPUT_ENABLED +#define appconfINTENT_I2C_MASTER_OUTPUT_ENABLED 1 #endif -#ifndef appconfINTENT_I2C_OUTPUT_DEVICE_ADDR -#define appconfINTENT_I2C_OUTPUT_DEVICE_ADDR 0x01 +#ifndef appconfINTENT_I2C_MASTER_DEVICE_ADDR +#define appconfINTENT_I2C_MASTER_DEVICE_ADDR 0x01 +#endif + +/* @brief Address for wakeword register to be read over I2C slave*/ +#ifndef appconfINTENT_I2C_REG_ADDRESS +#define appconfINTENT_I2C_REG_ADDRESS 0x01 #endif #ifndef appconfINTENT_UART_OUTPUT_ENABLED #define appconfINTENT_UART_OUTPUT_ENABLED 1 #endif +#ifndef appconfINTENT_UART_DEBUG_INFO_ENABLED +#define appconfINTENT_UART_DEBUG_INFO_ENABLED 0 +#endif + #ifndef appconfUART_BAUD_RATE #define appconfUART_BAUD_RATE 9600 #endif +#ifndef appconfI2S_MODE_MASTER +#define appconfI2S_MODE_MASTER 0 +#endif + +#ifndef appconfI2S_MODE_SLAVE +#define appconfI2S_MODE_SLAVE 1 +#endif + #ifndef appconfI2S_ENABLED -#define appconfI2S_ENABLED 1 +#define appconfI2S_ENABLED 1 +#endif + +#ifndef appconfI2S_MODE +#define appconfI2S_MODE appconfI2S_MODE_MASTER +#endif + +#ifndef appconfUSE_I2S_INPUT +#define appconfUSE_I2S_INPUT 0 +#endif + +#if appconfUSE_I2S_INPUT && !appconfI2S_ENABLED +#error "I2S must be enabled if receiving the audio over I2S" +#endif + +#ifndef appconfINTENT_I2C_MASTER_OUTPUT_ENABLED +#define appconfINTENT_I2C_MASTER_OUTPUT_ENABLED 1 +#endif + +#ifndef appconfI2C_MASTER_DAC_ENABLED +#define appconfI2C_MASTER_DAC_ENABLED 1 +#endif + +#ifndef appconfI2C_SLAVE_DEVICE_ADDR +#define appconfI2C_SLAVE_DEVICE_ADDR 0x42 +#endif + +#if appconfINTENT_I2C_MASTER_OUTPUT_ENABLED && appconfINTENT_I2C_SLAVE_POLLED_ENABLED +#error "The intent message cannot be sent over I2C master and polled via I2C slave simultaneously" #endif #ifndef appconfAUDIO_PIPELINE_SKIP_IC_AND_VNR @@ -124,6 +170,18 @@ #define appconfQSPI_FLASH_TASK_PRIORITY (configMAX_PRIORITIES - 1) #define appconfLED_TASK_PRIORITY (configMAX_PRIORITIES / 2 - 1) +#if appconfI2S_MODE==appconfI2S_MODE_SLAVE +/* Software PLL settings for mclk recovery configurations */ +/* see fractions.h and register_setup.h for other pll settings */ +#define appconfLRCLK_NOMINAL_HZ appconfI2S_AUDIO_SAMPLE_RATE +#define appconfBCLK_NOMINAL_HZ (appconfLRCLK_NOMINAL_HZ * 64) +#define PLL_RATIO (MIC_ARRAY_CONFIG_MCLK_FREQ / appconfLRCLK_NOMINAL_HZ) +#define PLL_CONTROL_LOOP_COUNT_INT 512 // How many refclk ticks (LRCLK) per control loop iteration. Aim for ~100Hz +#define PLL_PPM_RANGE 1000 // Max allowable diff in clk count. For the PID constants we + // have chosen, this number should be larger than the number + // of elements in the look up table as the clk count diff is + // added to the LUT index with a multiplier of 1. Only used for INT mclkless +#endif #include "app_conf_check.h" #endif /* APP_CONF_H_ */ diff --git a/examples/ffd/src/device_memory_impl.h b/examples/ffd/src/device_memory_impl.h deleted file mode 100644 index 0822a303c..000000000 --- a/examples/ffd/src/device_memory_impl.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2023 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. -#ifndef DEVICE_MEMORY_IMPL_H -#define DEVICE_MEMORY_IMPL_H - -#include "device_memory.h" - -void devmem_init(devmem_manager_t *devmem_ctx); - -#endif // DEVICE_MEMORY_IMPL_H \ No newline at end of file diff --git a/examples/ffd/src/fractions_1000ppm.h b/examples/ffd/src/fractions_1000ppm.h new file mode 100644 index 000000000..9c9ed1b8f --- /dev/null +++ b/examples/ffd/src/fractions_1000ppm.h @@ -0,0 +1,796 @@ +// Copyright 2023-2024 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. +static short frac_values_90[790] = { +0x1832, // Index: 0 Fraction: 25/51 = 0.4902 +0x1934, // Index: 1 Fraction: 26/53 = 0.4906 +0x1A36, // Index: 2 Fraction: 27/55 = 0.4909 +0x1B38, // Index: 3 Fraction: 28/57 = 0.4912 +0x1C3A, // Index: 4 Fraction: 29/59 = 0.4915 +0x1D3C, // Index: 5 Fraction: 30/61 = 0.4918 +0x1E3E, // Index: 6 Fraction: 31/63 = 0.4921 +0x1F40, // Index: 7 Fraction: 32/65 = 0.4923 +0x2042, // Index: 8 Fraction: 33/67 = 0.4925 +0x2144, // Index: 9 Fraction: 34/69 = 0.4928 +0x2246, // Index: 10 Fraction: 35/71 = 0.4930 +0x2348, // Index: 11 Fraction: 36/73 = 0.4932 +0x244A, // Index: 12 Fraction: 37/75 = 0.4933 +0x254C, // Index: 13 Fraction: 38/77 = 0.4935 +0x264E, // Index: 14 Fraction: 39/79 = 0.4937 +0x2750, // Index: 15 Fraction: 40/81 = 0.4938 +0x2852, // Index: 16 Fraction: 41/83 = 0.4940 +0x2954, // Index: 17 Fraction: 42/85 = 0.4941 +0x2A56, // Index: 18 Fraction: 43/87 = 0.4943 +0x2B58, // Index: 19 Fraction: 44/89 = 0.4944 +0x0001, // Index: 20 Fraction: 1/2 = 0.5000 +0x2C58, // Index: 21 Fraction: 45/89 = 0.5056 +0x2B56, // Index: 22 Fraction: 44/87 = 0.5057 +0x2A54, // Index: 23 Fraction: 43/85 = 0.5059 +0x2952, // Index: 24 Fraction: 42/83 = 0.5060 +0x2850, // Index: 25 Fraction: 41/81 = 0.5062 +0x274E, // Index: 26 Fraction: 40/79 = 0.5063 +0x264C, // Index: 27 Fraction: 39/77 = 0.5065 +0x254A, // Index: 28 Fraction: 38/75 = 0.5067 +0x2448, // Index: 29 Fraction: 37/73 = 0.5068 +0x2346, // Index: 30 Fraction: 36/71 = 0.5070 +0x2244, // Index: 31 Fraction: 35/69 = 0.5072 +0x2142, // Index: 32 Fraction: 34/67 = 0.5075 +0x2040, // Index: 33 Fraction: 33/65 = 0.5077 +0x1F3E, // Index: 34 Fraction: 32/63 = 0.5079 +0x1E3C, // Index: 35 Fraction: 31/61 = 0.5082 +0x1D3A, // Index: 36 Fraction: 30/59 = 0.5085 +0x1C38, // Index: 37 Fraction: 29/57 = 0.5088 +0x1B36, // Index: 38 Fraction: 28/55 = 0.5091 +0x1A34, // Index: 39 Fraction: 27/53 = 0.5094 +0x1932, // Index: 40 Fraction: 26/51 = 0.5098 +0x1830, // Index: 41 Fraction: 25/49 = 0.5102 +0x172E, // Index: 42 Fraction: 24/47 = 0.5106 +0x162C, // Index: 43 Fraction: 23/45 = 0.5111 +0x2C57, // Index: 44 Fraction: 45/88 = 0.5114 +0x152A, // Index: 45 Fraction: 22/43 = 0.5116 +0x2A53, // Index: 46 Fraction: 43/84 = 0.5119 +0x1428, // Index: 47 Fraction: 21/41 = 0.5122 +0x284F, // Index: 48 Fraction: 41/80 = 0.5125 +0x1326, // Index: 49 Fraction: 20/39 = 0.5128 +0x264B, // Index: 50 Fraction: 39/76 = 0.5132 +0x1224, // Index: 51 Fraction: 19/37 = 0.5135 +0x2447, // Index: 52 Fraction: 37/72 = 0.5139 +0x1122, // Index: 53 Fraction: 18/35 = 0.5143 +0x2243, // Index: 54 Fraction: 35/68 = 0.5147 +0x1020, // Index: 55 Fraction: 17/33 = 0.5152 +0x203F, // Index: 56 Fraction: 33/64 = 0.5156 +0x0F1E, // Index: 57 Fraction: 16/31 = 0.5161 +0x1E3B, // Index: 58 Fraction: 31/60 = 0.5167 +0x2D58, // Index: 59 Fraction: 46/89 = 0.5169 +0x0E1C, // Index: 60 Fraction: 15/29 = 0.5172 +0x2B54, // Index: 61 Fraction: 44/85 = 0.5176 +0x1C37, // Index: 62 Fraction: 29/56 = 0.5179 +0x2A52, // Index: 63 Fraction: 43/83 = 0.5181 +0x0D1A, // Index: 64 Fraction: 14/27 = 0.5185 +0x284E, // Index: 65 Fraction: 41/79 = 0.5190 +0x1A33, // Index: 66 Fraction: 27/52 = 0.5192 +0x274C, // Index: 67 Fraction: 40/77 = 0.5195 +0x0C18, // Index: 68 Fraction: 13/25 = 0.5200 +0x2548, // Index: 69 Fraction: 38/73 = 0.5205 +0x182F, // Index: 70 Fraction: 25/48 = 0.5208 +0x2446, // Index: 71 Fraction: 37/71 = 0.5211 +0x0B16, // Index: 72 Fraction: 12/23 = 0.5217 +0x2E59, // Index: 73 Fraction: 47/90 = 0.5222 +0x2242, // Index: 74 Fraction: 35/67 = 0.5224 +0x162B, // Index: 75 Fraction: 23/44 = 0.5227 +0x2140, // Index: 76 Fraction: 34/65 = 0.5231 +0x2C55, // Index: 77 Fraction: 45/86 = 0.5233 +0x0A14, // Index: 78 Fraction: 11/21 = 0.5238 +0x2A51, // Index: 79 Fraction: 43/82 = 0.5244 +0x1F3C, // Index: 80 Fraction: 32/61 = 0.5246 +0x1427, // Index: 81 Fraction: 21/40 = 0.5250 +0x1E3A, // Index: 82 Fraction: 31/59 = 0.5254 +0x284D, // Index: 83 Fraction: 41/78 = 0.5256 +0x0912, // Index: 84 Fraction: 10/19 = 0.5263 +0x2649, // Index: 85 Fraction: 39/74 = 0.5270 +0x1C36, // Index: 86 Fraction: 29/55 = 0.5273 +0x1223, // Index: 87 Fraction: 19/36 = 0.5278 +0x2E58, // Index: 88 Fraction: 47/89 = 0.5281 +0x1B34, // Index: 89 Fraction: 28/53 = 0.5283 +0x2445, // Index: 90 Fraction: 37/70 = 0.5286 +0x2D56, // Index: 91 Fraction: 46/87 = 0.5287 +0x0810, // Index: 92 Fraction: 9/17 = 0.5294 +0x2B52, // Index: 93 Fraction: 44/83 = 0.5301 +0x2241, // Index: 94 Fraction: 35/66 = 0.5303 +0x1930, // Index: 95 Fraction: 26/49 = 0.5306 +0x2A50, // Index: 96 Fraction: 43/81 = 0.5309 +0x101F, // Index: 97 Fraction: 17/32 = 0.5312 +0x294E, // Index: 98 Fraction: 42/79 = 0.5316 +0x182E, // Index: 99 Fraction: 25/47 = 0.5319 +0x203D, // Index: 100 Fraction: 33/62 = 0.5323 +0x284C, // Index: 101 Fraction: 41/77 = 0.5325 +0x070E, // Index: 102 Fraction: 8/15 = 0.5333 +0x2E57, // Index: 103 Fraction: 47/88 = 0.5341 +0x2648, // Index: 104 Fraction: 39/73 = 0.5342 +0x1E39, // Index: 105 Fraction: 31/58 = 0.5345 +0x162A, // Index: 106 Fraction: 23/43 = 0.5349 +0x2546, // Index: 107 Fraction: 38/71 = 0.5352 +0x0E1B, // Index: 108 Fraction: 15/28 = 0.5357 +0x2444, // Index: 109 Fraction: 37/69 = 0.5362 +0x1528, // Index: 110 Fraction: 22/41 = 0.5366 +0x1C35, // Index: 111 Fraction: 29/54 = 0.5370 +0x2342, // Index: 112 Fraction: 36/67 = 0.5373 +0x2A4F, // Index: 113 Fraction: 43/80 = 0.5375 +0x060C, // Index: 114 Fraction: 7/13 = 0.5385 +0x2F58, // Index: 115 Fraction: 48/89 = 0.5393 +0x284B, // Index: 116 Fraction: 41/76 = 0.5395 +0x213E, // Index: 117 Fraction: 34/63 = 0.5397 +0x1A31, // Index: 118 Fraction: 27/50 = 0.5400 +0x2E56, // Index: 119 Fraction: 47/87 = 0.5402 +0x1324, // Index: 120 Fraction: 20/37 = 0.5405 +0x203C, // Index: 121 Fraction: 33/61 = 0.5410 +0x2D54, // Index: 122 Fraction: 46/85 = 0.5412 +0x0C17, // Index: 123 Fraction: 13/24 = 0.5417 +0x2C52, // Index: 124 Fraction: 45/83 = 0.5422 +0x1F3A, // Index: 125 Fraction: 32/59 = 0.5424 +0x1222, // Index: 126 Fraction: 19/35 = 0.5429 +0x2B50, // Index: 127 Fraction: 44/81 = 0.5432 +0x182D, // Index: 128 Fraction: 25/46 = 0.5435 +0x1E38, // Index: 129 Fraction: 31/57 = 0.5439 +0x2443, // Index: 130 Fraction: 37/68 = 0.5441 +0x2A4E, // Index: 131 Fraction: 43/79 = 0.5443 +0x3059, // Index: 132 Fraction: 49/90 = 0.5444 +0x050A, // Index: 133 Fraction: 6/11 = 0.5455 +0x2E55, // Index: 134 Fraction: 47/86 = 0.5465 +0x284A, // Index: 135 Fraction: 41/75 = 0.5467 +0x223F, // Index: 136 Fraction: 35/64 = 0.5469 +0x1C34, // Index: 137 Fraction: 29/53 = 0.5472 +0x1629, // Index: 138 Fraction: 23/42 = 0.5476 +0x2748, // Index: 139 Fraction: 40/73 = 0.5479 +0x101E, // Index: 140 Fraction: 17/31 = 0.5484 +0x2C51, // Index: 141 Fraction: 45/82 = 0.5488 +0x1B32, // Index: 142 Fraction: 28/51 = 0.5490 +0x2646, // Index: 143 Fraction: 39/71 = 0.5493 +0x0A13, // Index: 144 Fraction: 11/20 = 0.5500 +0x3058, // Index: 145 Fraction: 49/89 = 0.5506 +0x2544, // Index: 146 Fraction: 38/69 = 0.5507 +0x1A30, // Index: 147 Fraction: 27/49 = 0.5510 +0x2A4D, // Index: 148 Fraction: 43/78 = 0.5513 +0x0F1C, // Index: 149 Fraction: 16/29 = 0.5517 +0x2442, // Index: 150 Fraction: 37/67 = 0.5522 +0x1425, // Index: 151 Fraction: 21/38 = 0.5526 +0x2E54, // Index: 152 Fraction: 47/85 = 0.5529 +0x192E, // Index: 153 Fraction: 26/47 = 0.5532 +0x1E37, // Index: 154 Fraction: 31/56 = 0.5536 +0x2340, // Index: 155 Fraction: 36/65 = 0.5538 +0x2849, // Index: 156 Fraction: 41/74 = 0.5541 +0x2D52, // Index: 157 Fraction: 46/83 = 0.5542 +0x0408, // Index: 158 Fraction: 5/9 = 0.5556 +0x3057, // Index: 159 Fraction: 49/88 = 0.5568 +0x2B4E, // Index: 160 Fraction: 44/79 = 0.5570 +0x2645, // Index: 161 Fraction: 39/70 = 0.5571 +0x213C, // Index: 162 Fraction: 34/61 = 0.5574 +0x1C33, // Index: 163 Fraction: 29/52 = 0.5577 +0x172A, // Index: 164 Fraction: 24/43 = 0.5581 +0x2A4C, // Index: 165 Fraction: 43/77 = 0.5584 +0x1221, // Index: 166 Fraction: 19/34 = 0.5588 +0x203A, // Index: 167 Fraction: 33/59 = 0.5593 +0x2E53, // Index: 168 Fraction: 47/84 = 0.5595 +0x0D18, // Index: 169 Fraction: 14/25 = 0.5600 +0x2441, // Index: 170 Fraction: 37/66 = 0.5606 +0x1628, // Index: 171 Fraction: 23/41 = 0.5610 +0x1F38, // Index: 172 Fraction: 32/57 = 0.5614 +0x2848, // Index: 173 Fraction: 41/73 = 0.5616 +0x3158, // Index: 174 Fraction: 50/89 = 0.5618 +0x080F, // Index: 175 Fraction: 9/16 = 0.5625 +0x3056, // Index: 176 Fraction: 49/87 = 0.5632 +0x2746, // Index: 177 Fraction: 40/71 = 0.5634 +0x1E36, // Index: 178 Fraction: 31/55 = 0.5636 +0x1526, // Index: 179 Fraction: 22/39 = 0.5641 +0x223D, // Index: 180 Fraction: 35/62 = 0.5645 +0x2F54, // Index: 181 Fraction: 48/85 = 0.5647 +0x0C16, // Index: 182 Fraction: 13/23 = 0.5652 +0x2A4B, // Index: 183 Fraction: 43/76 = 0.5658 +0x1D34, // Index: 184 Fraction: 30/53 = 0.5660 +0x2E52, // Index: 185 Fraction: 47/83 = 0.5663 +0x101D, // Index: 186 Fraction: 17/30 = 0.5667 +0x2542, // Index: 187 Fraction: 38/67 = 0.5672 +0x1424, // Index: 188 Fraction: 21/37 = 0.5676 +0x2D50, // Index: 189 Fraction: 46/81 = 0.5679 +0x182B, // Index: 190 Fraction: 25/44 = 0.5682 +0x1C32, // Index: 191 Fraction: 29/51 = 0.5686 +0x2039, // Index: 192 Fraction: 33/58 = 0.5690 +0x2440, // Index: 193 Fraction: 37/65 = 0.5692 +0x2847, // Index: 194 Fraction: 41/72 = 0.5694 +0x2C4E, // Index: 195 Fraction: 45/79 = 0.5696 +0x3055, // Index: 196 Fraction: 49/86 = 0.5698 +0x0306, // Index: 197 Fraction: 4/7 = 0.5714 +0x3258, // Index: 198 Fraction: 51/89 = 0.5730 +0x2E51, // Index: 199 Fraction: 47/82 = 0.5732 +0x2A4A, // Index: 200 Fraction: 43/75 = 0.5733 +0x2643, // Index: 201 Fraction: 39/68 = 0.5735 +0x223C, // Index: 202 Fraction: 35/61 = 0.5738 +0x1E35, // Index: 203 Fraction: 31/54 = 0.5741 +0x1A2E, // Index: 204 Fraction: 27/47 = 0.5745 +0x3156, // Index: 205 Fraction: 50/87 = 0.5747 +0x1627, // Index: 206 Fraction: 23/40 = 0.5750 +0x2948, // Index: 207 Fraction: 42/73 = 0.5753 +0x1220, // Index: 208 Fraction: 19/33 = 0.5758 +0x213A, // Index: 209 Fraction: 34/59 = 0.5763 +0x3054, // Index: 210 Fraction: 49/85 = 0.5765 +0x0E19, // Index: 211 Fraction: 15/26 = 0.5769 +0x2846, // Index: 212 Fraction: 41/71 = 0.5775 +0x192C, // Index: 213 Fraction: 26/45 = 0.5778 +0x243F, // Index: 214 Fraction: 37/64 = 0.5781 +0x2F52, // Index: 215 Fraction: 48/83 = 0.5783 +0x0A12, // Index: 216 Fraction: 11/19 = 0.5789 +0x3257, // Index: 217 Fraction: 51/88 = 0.5795 +0x2744, // Index: 218 Fraction: 40/69 = 0.5797 +0x1C31, // Index: 219 Fraction: 29/50 = 0.5800 +0x2E50, // Index: 220 Fraction: 47/81 = 0.5802 +0x111E, // Index: 221 Fraction: 18/31 = 0.5806 +0x2A49, // Index: 222 Fraction: 43/74 = 0.5811 +0x182A, // Index: 223 Fraction: 25/43 = 0.5814 +0x1F36, // Index: 224 Fraction: 32/55 = 0.5818 +0x2642, // Index: 225 Fraction: 39/67 = 0.5821 +0x2D4E, // Index: 226 Fraction: 46/79 = 0.5823 +0x060B, // Index: 227 Fraction: 7/12 = 0.5833 +0x3358, // Index: 228 Fraction: 52/89 = 0.5843 +0x2C4C, // Index: 229 Fraction: 45/77 = 0.5844 +0x2540, // Index: 230 Fraction: 38/65 = 0.5846 +0x1E34, // Index: 231 Fraction: 31/53 = 0.5849 +0x1728, // Index: 232 Fraction: 24/41 = 0.5854 +0x2845, // Index: 233 Fraction: 41/70 = 0.5857 +0x101C, // Index: 234 Fraction: 17/29 = 0.5862 +0x2B4A, // Index: 235 Fraction: 44/75 = 0.5867 +0x1A2D, // Index: 236 Fraction: 27/46 = 0.5870 +0x243E, // Index: 237 Fraction: 37/63 = 0.5873 +0x2E4F, // Index: 238 Fraction: 47/80 = 0.5875 +0x0910, // Index: 239 Fraction: 10/17 = 0.5882 +0x3459, // Index: 240 Fraction: 53/90 = 0.5889 +0x2A48, // Index: 241 Fraction: 43/73 = 0.5890 +0x2037, // Index: 242 Fraction: 33/56 = 0.5893 +0x1626, // Index: 243 Fraction: 23/39 = 0.5897 +0x233C, // Index: 244 Fraction: 36/61 = 0.5902 +0x3052, // Index: 245 Fraction: 49/83 = 0.5904 +0x0C15, // Index: 246 Fraction: 13/22 = 0.5909 +0x2946, // Index: 247 Fraction: 42/71 = 0.5915 +0x1C30, // Index: 248 Fraction: 29/49 = 0.5918 +0x2C4B, // Index: 249 Fraction: 45/76 = 0.5921 +0x0F1A, // Index: 250 Fraction: 16/27 = 0.5926 +0x3255, // Index: 251 Fraction: 51/86 = 0.5930 +0x223A, // Index: 252 Fraction: 35/59 = 0.5932 +0x121F, // Index: 253 Fraction: 19/32 = 0.5938 +0x2844, // Index: 254 Fraction: 41/69 = 0.5942 +0x1524, // Index: 255 Fraction: 22/37 = 0.5946 +0x2E4E, // Index: 256 Fraction: 47/79 = 0.5949 +0x1829, // Index: 257 Fraction: 25/42 = 0.5952 +0x3458, // Index: 258 Fraction: 53/89 = 0.5955 +0x1B2E, // Index: 259 Fraction: 28/47 = 0.5957 +0x1E33, // Index: 260 Fraction: 31/52 = 0.5962 +0x2138, // Index: 261 Fraction: 34/57 = 0.5965 +0x243D, // Index: 262 Fraction: 37/62 = 0.5968 +0x2742, // Index: 263 Fraction: 40/67 = 0.5970 +0x2A47, // Index: 264 Fraction: 43/72 = 0.5972 +0x2D4C, // Index: 265 Fraction: 46/77 = 0.5974 +0x3051, // Index: 266 Fraction: 49/82 = 0.5976 +0x3356, // Index: 267 Fraction: 52/87 = 0.5977 +0x0204, // Index: 268 Fraction: 3/5 = 0.6000 +0x3457, // Index: 269 Fraction: 53/88 = 0.6023 +0x3152, // Index: 270 Fraction: 50/83 = 0.6024 +0x2E4D, // Index: 271 Fraction: 47/78 = 0.6026 +0x2B48, // Index: 272 Fraction: 44/73 = 0.6027 +0x2843, // Index: 273 Fraction: 41/68 = 0.6029 +0x253E, // Index: 274 Fraction: 38/63 = 0.6032 +0x2239, // Index: 275 Fraction: 35/58 = 0.6034 +0x1F34, // Index: 276 Fraction: 32/53 = 0.6038 +0x1C2F, // Index: 277 Fraction: 29/48 = 0.6042 +0x192A, // Index: 278 Fraction: 26/43 = 0.6047 +0x3050, // Index: 279 Fraction: 49/81 = 0.6049 +0x1625, // Index: 280 Fraction: 23/38 = 0.6053 +0x2A46, // Index: 281 Fraction: 43/71 = 0.6056 +0x1320, // Index: 282 Fraction: 20/33 = 0.6061 +0x243C, // Index: 283 Fraction: 37/61 = 0.6066 +0x3558, // Index: 284 Fraction: 54/89 = 0.6067 +0x101B, // Index: 285 Fraction: 17/28 = 0.6071 +0x2F4E, // Index: 286 Fraction: 48/79 = 0.6076 +0x1E32, // Index: 287 Fraction: 31/51 = 0.6078 +0x2C49, // Index: 288 Fraction: 45/74 = 0.6081 +0x0D16, // Index: 289 Fraction: 14/23 = 0.6087 +0x3456, // Index: 290 Fraction: 53/87 = 0.6092 +0x263F, // Index: 291 Fraction: 39/64 = 0.6094 +0x1828, // Index: 292 Fraction: 25/41 = 0.6098 +0x233A, // Index: 293 Fraction: 36/59 = 0.6102 +0x2E4C, // Index: 294 Fraction: 47/77 = 0.6104 +0x0A11, // Index: 295 Fraction: 11/18 = 0.6111 +0x3354, // Index: 296 Fraction: 52/85 = 0.6118 +0x2842, // Index: 297 Fraction: 41/67 = 0.6119 +0x1D30, // Index: 298 Fraction: 30/49 = 0.6122 +0x304F, // Index: 299 Fraction: 49/80 = 0.6125 +0x121E, // Index: 300 Fraction: 19/31 = 0.6129 +0x2D4A, // Index: 301 Fraction: 46/75 = 0.6133 +0x1A2B, // Index: 302 Fraction: 27/44 = 0.6136 +0x2238, // Index: 303 Fraction: 35/57 = 0.6140 +0x2A45, // Index: 304 Fraction: 43/70 = 0.6143 +0x3252, // Index: 305 Fraction: 51/83 = 0.6145 +0x070C, // Index: 306 Fraction: 8/13 = 0.6154 +0x3455, // Index: 307 Fraction: 53/86 = 0.6163 +0x2C48, // Index: 308 Fraction: 45/73 = 0.6164 +0x243B, // Index: 309 Fraction: 37/60 = 0.6167 +0x1C2E, // Index: 310 Fraction: 29/47 = 0.6170 +0x3150, // Index: 311 Fraction: 50/81 = 0.6173 +0x1421, // Index: 312 Fraction: 21/34 = 0.6176 +0x3658, // Index: 313 Fraction: 55/89 = 0.6180 +0x2136, // Index: 314 Fraction: 34/55 = 0.6182 +0x2E4B, // Index: 315 Fraction: 47/76 = 0.6184 +0x0C14, // Index: 316 Fraction: 13/21 = 0.6190 +0x2B46, // Index: 317 Fraction: 44/71 = 0.6197 +0x1E31, // Index: 318 Fraction: 31/50 = 0.6200 +0x304E, // Index: 319 Fraction: 49/79 = 0.6203 +0x111C, // Index: 320 Fraction: 18/29 = 0.6207 +0x2841, // Index: 321 Fraction: 41/66 = 0.6212 +0x1624, // Index: 322 Fraction: 23/37 = 0.6216 +0x3251, // Index: 323 Fraction: 51/82 = 0.6220 +0x1B2C, // Index: 324 Fraction: 28/45 = 0.6222 +0x2034, // Index: 325 Fraction: 33/53 = 0.6226 +0x253C, // Index: 326 Fraction: 38/61 = 0.6230 +0x2A44, // Index: 327 Fraction: 43/69 = 0.6232 +0x2F4C, // Index: 328 Fraction: 48/77 = 0.6234 +0x3454, // Index: 329 Fraction: 53/85 = 0.6235 +0x0407, // Index: 330 Fraction: 5/8 = 0.6250 +0x3352, // Index: 331 Fraction: 52/83 = 0.6265 +0x2E4A, // Index: 332 Fraction: 47/75 = 0.6267 +0x2942, // Index: 333 Fraction: 42/67 = 0.6269 +0x243A, // Index: 334 Fraction: 37/59 = 0.6271 +0x1F32, // Index: 335 Fraction: 32/51 = 0.6275 +0x1A2A, // Index: 336 Fraction: 27/43 = 0.6279 +0x304D, // Index: 337 Fraction: 49/78 = 0.6282 +0x1522, // Index: 338 Fraction: 22/35 = 0.6286 +0x263D, // Index: 339 Fraction: 39/62 = 0.6290 +0x3758, // Index: 340 Fraction: 56/89 = 0.6292 +0x101A, // Index: 341 Fraction: 17/27 = 0.6296 +0x2D48, // Index: 342 Fraction: 46/73 = 0.6301 +0x1C2D, // Index: 343 Fraction: 29/46 = 0.6304 +0x2840, // Index: 344 Fraction: 41/65 = 0.6308 +0x3453, // Index: 345 Fraction: 53/84 = 0.6310 +0x0B12, // Index: 346 Fraction: 12/19 = 0.6316 +0x3656, // Index: 347 Fraction: 55/87 = 0.6322 +0x2A43, // Index: 348 Fraction: 43/68 = 0.6324 +0x1E30, // Index: 349 Fraction: 31/49 = 0.6327 +0x314E, // Index: 350 Fraction: 50/79 = 0.6329 +0x121D, // Index: 351 Fraction: 19/30 = 0.6333 +0x2C46, // Index: 352 Fraction: 45/71 = 0.6338 +0x1928, // Index: 353 Fraction: 26/41 = 0.6341 +0x2033, // Index: 354 Fraction: 33/52 = 0.6346 +0x273E, // Index: 355 Fraction: 40/63 = 0.6349 +0x2E49, // Index: 356 Fraction: 47/74 = 0.6351 +0x3554, // Index: 357 Fraction: 54/85 = 0.6353 +0x060A, // Index: 358 Fraction: 7/11 = 0.6364 +0x324F, // Index: 359 Fraction: 51/80 = 0.6375 +0x2B44, // Index: 360 Fraction: 44/69 = 0.6377 +0x2439, // Index: 361 Fraction: 37/58 = 0.6379 +0x1D2E, // Index: 362 Fraction: 30/47 = 0.6383 +0x3452, // Index: 363 Fraction: 53/83 = 0.6386 +0x1623, // Index: 364 Fraction: 23/36 = 0.6389 +0x263C, // Index: 365 Fraction: 39/61 = 0.6393 +0x3655, // Index: 366 Fraction: 55/86 = 0.6395 +0x0F18, // Index: 367 Fraction: 16/25 = 0.6400 +0x3858, // Index: 368 Fraction: 57/89 = 0.6404 +0x283F, // Index: 369 Fraction: 41/64 = 0.6406 +0x1826, // Index: 370 Fraction: 25/39 = 0.6410 +0x2134, // Index: 371 Fraction: 34/53 = 0.6415 +0x2A42, // Index: 372 Fraction: 43/67 = 0.6418 +0x3350, // Index: 373 Fraction: 52/81 = 0.6420 +0x080D, // Index: 374 Fraction: 9/14 = 0.6429 +0x3756, // Index: 375 Fraction: 56/87 = 0.6437 +0x2E48, // Index: 376 Fraction: 47/73 = 0.6438 +0x253A, // Index: 377 Fraction: 38/59 = 0.6441 +0x1C2C, // Index: 378 Fraction: 29/45 = 0.6444 +0x304B, // Index: 379 Fraction: 49/76 = 0.6447 +0x131E, // Index: 380 Fraction: 20/31 = 0.6452 +0x324E, // Index: 381 Fraction: 51/79 = 0.6456 +0x1E2F, // Index: 382 Fraction: 31/48 = 0.6458 +0x2940, // Index: 383 Fraction: 42/65 = 0.6462 +0x3451, // Index: 384 Fraction: 53/82 = 0.6463 +0x0A10, // Index: 385 Fraction: 11/17 = 0.6471 +0x3857, // Index: 386 Fraction: 57/88 = 0.6477 +0x2D46, // Index: 387 Fraction: 46/71 = 0.6479 +0x2235, // Index: 388 Fraction: 35/54 = 0.6481 +0x1724, // Index: 389 Fraction: 24/37 = 0.6486 +0x2438, // Index: 390 Fraction: 37/57 = 0.6491 +0x314C, // Index: 391 Fraction: 50/77 = 0.6494 +0x0C13, // Index: 392 Fraction: 13/20 = 0.6500 +0x3552, // Index: 393 Fraction: 54/83 = 0.6506 +0x283E, // Index: 394 Fraction: 41/63 = 0.6508 +0x1B2A, // Index: 395 Fraction: 28/43 = 0.6512 +0x2A41, // Index: 396 Fraction: 43/66 = 0.6515 +0x3958, // Index: 397 Fraction: 58/89 = 0.6517 +0x0E16, // Index: 398 Fraction: 15/23 = 0.6522 +0x2E47, // Index: 399 Fraction: 47/72 = 0.6528 +0x1F30, // Index: 400 Fraction: 32/49 = 0.6531 +0x304A, // Index: 401 Fraction: 49/75 = 0.6533 +0x1019, // Index: 402 Fraction: 17/26 = 0.6538 +0x3450, // Index: 403 Fraction: 53/81 = 0.6543 +0x2336, // Index: 404 Fraction: 36/55 = 0.6545 +0x3653, // Index: 405 Fraction: 55/84 = 0.6548 +0x121C, // Index: 406 Fraction: 19/29 = 0.6552 +0x3A59, // Index: 407 Fraction: 59/90 = 0.6556 +0x273C, // Index: 408 Fraction: 40/61 = 0.6557 +0x141F, // Index: 409 Fraction: 21/32 = 0.6562 +0x2B42, // Index: 410 Fraction: 44/67 = 0.6567 +0x1622, // Index: 411 Fraction: 23/35 = 0.6571 +0x2F48, // Index: 412 Fraction: 48/73 = 0.6575 +0x1825, // Index: 413 Fraction: 25/38 = 0.6579 +0x334E, // Index: 414 Fraction: 52/79 = 0.6582 +0x1A28, // Index: 415 Fraction: 27/41 = 0.6585 +0x3754, // Index: 416 Fraction: 56/85 = 0.6588 +0x1C2B, // Index: 417 Fraction: 29/44 = 0.6591 +0x1E2E, // Index: 418 Fraction: 31/47 = 0.6596 +0x2031, // Index: 419 Fraction: 33/50 = 0.6600 +0x2234, // Index: 420 Fraction: 35/53 = 0.6604 +0x2437, // Index: 421 Fraction: 37/56 = 0.6607 +0x263A, // Index: 422 Fraction: 39/59 = 0.6610 +0x283D, // Index: 423 Fraction: 41/62 = 0.6613 +0x2A40, // Index: 424 Fraction: 43/65 = 0.6615 +0x2C43, // Index: 425 Fraction: 45/68 = 0.6618 +0x2E46, // Index: 426 Fraction: 47/71 = 0.6620 +0x3049, // Index: 427 Fraction: 49/74 = 0.6622 +0x324C, // Index: 428 Fraction: 51/77 = 0.6623 +0x344F, // Index: 429 Fraction: 53/80 = 0.6625 +0x3652, // Index: 430 Fraction: 55/83 = 0.6627 +0x3855, // Index: 431 Fraction: 57/86 = 0.6628 +0x3A58, // Index: 432 Fraction: 59/89 = 0.6629 +0x0102, // Index: 433 Fraction: 2/3 = 0.6667 +0x3A57, // Index: 434 Fraction: 59/88 = 0.6705 +0x3854, // Index: 435 Fraction: 57/85 = 0.6706 +0x3651, // Index: 436 Fraction: 55/82 = 0.6707 +0x344E, // Index: 437 Fraction: 53/79 = 0.6709 +0x324B, // Index: 438 Fraction: 51/76 = 0.6711 +0x3048, // Index: 439 Fraction: 49/73 = 0.6712 +0x2E45, // Index: 440 Fraction: 47/70 = 0.6714 +0x2C42, // Index: 441 Fraction: 45/67 = 0.6716 +0x2A3F, // Index: 442 Fraction: 43/64 = 0.6719 +0x283C, // Index: 443 Fraction: 41/61 = 0.6721 +0x2639, // Index: 444 Fraction: 39/58 = 0.6724 +0x2436, // Index: 445 Fraction: 37/55 = 0.6727 +0x2233, // Index: 446 Fraction: 35/52 = 0.6731 +0x2030, // Index: 447 Fraction: 33/49 = 0.6735 +0x1E2D, // Index: 448 Fraction: 31/46 = 0.6739 +0x3B58, // Index: 449 Fraction: 60/89 = 0.6742 +0x1C2A, // Index: 450 Fraction: 29/43 = 0.6744 +0x3752, // Index: 451 Fraction: 56/83 = 0.6747 +0x1A27, // Index: 452 Fraction: 27/40 = 0.6750 +0x334C, // Index: 453 Fraction: 52/77 = 0.6753 +0x1824, // Index: 454 Fraction: 25/37 = 0.6757 +0x2F46, // Index: 455 Fraction: 48/71 = 0.6761 +0x1621, // Index: 456 Fraction: 23/34 = 0.6765 +0x2B40, // Index: 457 Fraction: 44/65 = 0.6769 +0x141E, // Index: 458 Fraction: 21/31 = 0.6774 +0x3C59, // Index: 459 Fraction: 61/90 = 0.6778 +0x273A, // Index: 460 Fraction: 40/59 = 0.6780 +0x3A56, // Index: 461 Fraction: 59/87 = 0.6782 +0x121B, // Index: 462 Fraction: 19/28 = 0.6786 +0x3650, // Index: 463 Fraction: 55/81 = 0.6790 +0x2334, // Index: 464 Fraction: 36/53 = 0.6792 +0x344D, // Index: 465 Fraction: 53/78 = 0.6795 +0x1018, // Index: 466 Fraction: 17/25 = 0.6800 +0x3047, // Index: 467 Fraction: 49/72 = 0.6806 +0x1F2E, // Index: 468 Fraction: 32/47 = 0.6809 +0x2E44, // Index: 469 Fraction: 47/69 = 0.6812 +0x0E15, // Index: 470 Fraction: 15/22 = 0.6818 +0x3954, // Index: 471 Fraction: 58/85 = 0.6824 +0x2A3E, // Index: 472 Fraction: 43/63 = 0.6825 +0x1B28, // Index: 473 Fraction: 28/41 = 0.6829 +0x283B, // Index: 474 Fraction: 41/60 = 0.6833 +0x354E, // Index: 475 Fraction: 54/79 = 0.6835 +0x0C12, // Index: 476 Fraction: 13/19 = 0.6842 +0x3148, // Index: 477 Fraction: 50/73 = 0.6849 +0x2435, // Index: 478 Fraction: 37/54 = 0.6852 +0x3C58, // Index: 479 Fraction: 61/89 = 0.6854 +0x1722, // Index: 480 Fraction: 24/35 = 0.6857 +0x3A55, // Index: 481 Fraction: 59/86 = 0.6860 +0x2232, // Index: 482 Fraction: 35/51 = 0.6863 +0x2D42, // Index: 483 Fraction: 46/67 = 0.6866 +0x3852, // Index: 484 Fraction: 57/83 = 0.6867 +0x0A0F, // Index: 485 Fraction: 11/16 = 0.6875 +0x344C, // Index: 486 Fraction: 53/77 = 0.6883 +0x293C, // Index: 487 Fraction: 42/61 = 0.6885 +0x1E2C, // Index: 488 Fraction: 31/45 = 0.6889 +0x3249, // Index: 489 Fraction: 51/74 = 0.6892 +0x131C, // Index: 490 Fraction: 20/29 = 0.6897 +0x3046, // Index: 491 Fraction: 49/71 = 0.6901 +0x1C29, // Index: 492 Fraction: 29/42 = 0.6905 +0x2536, // Index: 493 Fraction: 38/55 = 0.6909 +0x2E43, // Index: 494 Fraction: 47/68 = 0.6912 +0x3750, // Index: 495 Fraction: 56/81 = 0.6914 +0x080C, // Index: 496 Fraction: 9/13 = 0.6923 +0x3C57, // Index: 497 Fraction: 61/88 = 0.6932 +0x334A, // Index: 498 Fraction: 52/75 = 0.6933 +0x2A3D, // Index: 499 Fraction: 43/62 = 0.6935 +0x2130, // Index: 500 Fraction: 34/49 = 0.6939 +0x3A54, // Index: 501 Fraction: 59/85 = 0.6941 +0x1823, // Index: 502 Fraction: 25/36 = 0.6944 +0x283A, // Index: 503 Fraction: 41/59 = 0.6949 +0x3851, // Index: 504 Fraction: 57/82 = 0.6951 +0x0F16, // Index: 505 Fraction: 16/23 = 0.6957 +0x364E, // Index: 506 Fraction: 55/79 = 0.6962 +0x2637, // Index: 507 Fraction: 39/56 = 0.6964 +0x3D58, // Index: 508 Fraction: 62/89 = 0.6966 +0x1620, // Index: 509 Fraction: 23/33 = 0.6970 +0x344B, // Index: 510 Fraction: 53/76 = 0.6974 +0x1D2A, // Index: 511 Fraction: 30/43 = 0.6977 +0x2434, // Index: 512 Fraction: 37/53 = 0.6981 +0x2B3E, // Index: 513 Fraction: 44/63 = 0.6984 +0x3248, // Index: 514 Fraction: 51/73 = 0.6986 +0x3952, // Index: 515 Fraction: 58/83 = 0.6988 +0x0609, // Index: 516 Fraction: 7/10 = 0.7000 +0x3C56, // Index: 517 Fraction: 61/87 = 0.7011 +0x354C, // Index: 518 Fraction: 54/77 = 0.7013 +0x2E42, // Index: 519 Fraction: 47/67 = 0.7015 +0x2738, // Index: 520 Fraction: 40/57 = 0.7018 +0x202E, // Index: 521 Fraction: 33/47 = 0.7021 +0x3A53, // Index: 522 Fraction: 59/84 = 0.7024 +0x1924, // Index: 523 Fraction: 26/37 = 0.7027 +0x2C3F, // Index: 524 Fraction: 45/64 = 0.7031 +0x121A, // Index: 525 Fraction: 19/27 = 0.7037 +0x3146, // Index: 526 Fraction: 50/71 = 0.7042 +0x1E2B, // Index: 527 Fraction: 31/44 = 0.7045 +0x2A3C, // Index: 528 Fraction: 43/61 = 0.7049 +0x364D, // Index: 529 Fraction: 55/78 = 0.7051 +0x0B10, // Index: 530 Fraction: 12/17 = 0.7059 +0x344A, // Index: 531 Fraction: 53/75 = 0.7067 +0x2839, // Index: 532 Fraction: 41/58 = 0.7069 +0x1C28, // Index: 533 Fraction: 29/41 = 0.7073 +0x2D40, // Index: 534 Fraction: 46/65 = 0.7077 +0x3E58, // Index: 535 Fraction: 63/89 = 0.7079 +0x1017, // Index: 536 Fraction: 17/24 = 0.7083 +0x374E, // Index: 537 Fraction: 56/79 = 0.7089 +0x2636, // Index: 538 Fraction: 39/55 = 0.7091 +0x3C55, // Index: 539 Fraction: 61/86 = 0.7093 +0x151E, // Index: 540 Fraction: 22/31 = 0.7097 +0x3044, // Index: 541 Fraction: 49/69 = 0.7101 +0x1A25, // Index: 542 Fraction: 27/38 = 0.7105 +0x3A52, // Index: 543 Fraction: 59/83 = 0.7108 +0x1F2C, // Index: 544 Fraction: 32/45 = 0.7111 +0x2433, // Index: 545 Fraction: 37/52 = 0.7115 +0x293A, // Index: 546 Fraction: 42/59 = 0.7119 +0x2E41, // Index: 547 Fraction: 47/66 = 0.7121 +0x3348, // Index: 548 Fraction: 52/73 = 0.7123 +0x384F, // Index: 549 Fraction: 57/80 = 0.7125 +0x3D56, // Index: 550 Fraction: 62/87 = 0.7126 +0x0406, // Index: 551 Fraction: 5/7 = 0.7143 +0x3E57, // Index: 552 Fraction: 63/88 = 0.7159 +0x3950, // Index: 553 Fraction: 58/81 = 0.7160 +0x3449, // Index: 554 Fraction: 53/74 = 0.7162 +0x2F42, // Index: 555 Fraction: 48/67 = 0.7164 +0x2A3B, // Index: 556 Fraction: 43/60 = 0.7167 +0x2534, // Index: 557 Fraction: 38/53 = 0.7170 +0x202D, // Index: 558 Fraction: 33/46 = 0.7174 +0x3C54, // Index: 559 Fraction: 61/85 = 0.7176 +0x1B26, // Index: 560 Fraction: 28/39 = 0.7179 +0x3246, // Index: 561 Fraction: 51/71 = 0.7183 +0x161F, // Index: 562 Fraction: 23/32 = 0.7188 +0x3F58, // Index: 563 Fraction: 64/89 = 0.7191 +0x2838, // Index: 564 Fraction: 41/57 = 0.7193 +0x3A51, // Index: 565 Fraction: 59/82 = 0.7195 +0x1118, // Index: 566 Fraction: 18/25 = 0.7200 +0x3043, // Index: 567 Fraction: 49/68 = 0.7206 +0x1E2A, // Index: 568 Fraction: 31/43 = 0.7209 +0x2B3C, // Index: 569 Fraction: 44/61 = 0.7213 +0x384E, // Index: 570 Fraction: 57/79 = 0.7215 +0x0C11, // Index: 571 Fraction: 13/18 = 0.7222 +0x3B52, // Index: 572 Fraction: 60/83 = 0.7229 +0x2E40, // Index: 573 Fraction: 47/65 = 0.7231 +0x212E, // Index: 574 Fraction: 34/47 = 0.7234 +0x364B, // Index: 575 Fraction: 55/76 = 0.7237 +0x141C, // Index: 576 Fraction: 21/29 = 0.7241 +0x3144, // Index: 577 Fraction: 50/69 = 0.7246 +0x1C27, // Index: 578 Fraction: 29/40 = 0.7250 +0x2432, // Index: 579 Fraction: 37/51 = 0.7255 +0x2C3D, // Index: 580 Fraction: 45/62 = 0.7258 +0x3448, // Index: 581 Fraction: 53/73 = 0.7260 +0x3C53, // Index: 582 Fraction: 61/84 = 0.7262 +0x070A, // Index: 583 Fraction: 8/11 = 0.7273 +0x3A50, // Index: 584 Fraction: 59/81 = 0.7284 +0x3245, // Index: 585 Fraction: 51/70 = 0.7286 +0x2A3A, // Index: 586 Fraction: 43/59 = 0.7288 +0x222F, // Index: 587 Fraction: 35/48 = 0.7292 +0x3D54, // Index: 588 Fraction: 62/85 = 0.7294 +0x1A24, // Index: 589 Fraction: 27/37 = 0.7297 +0x2D3E, // Index: 590 Fraction: 46/63 = 0.7302 +0x4058, // Index: 591 Fraction: 65/89 = 0.7303 +0x1219, // Index: 592 Fraction: 19/26 = 0.7308 +0x3042, // Index: 593 Fraction: 49/67 = 0.7313 +0x1D28, // Index: 594 Fraction: 30/41 = 0.7317 +0x2837, // Index: 595 Fraction: 41/56 = 0.7321 +0x3346, // Index: 596 Fraction: 52/71 = 0.7324 +0x3E55, // Index: 597 Fraction: 63/86 = 0.7326 +0x0A0E, // Index: 598 Fraction: 11/15 = 0.7333 +0x394E, // Index: 599 Fraction: 58/79 = 0.7342 +0x2E3F, // Index: 600 Fraction: 47/64 = 0.7344 +0x2330, // Index: 601 Fraction: 36/49 = 0.7347 +0x3C52, // Index: 602 Fraction: 61/83 = 0.7349 +0x1821, // Index: 603 Fraction: 25/34 = 0.7353 +0x3F56, // Index: 604 Fraction: 64/87 = 0.7356 +0x2634, // Index: 605 Fraction: 39/53 = 0.7358 +0x3447, // Index: 606 Fraction: 53/72 = 0.7361 +0x0D12, // Index: 607 Fraction: 14/19 = 0.7368 +0x3A4F, // Index: 608 Fraction: 59/80 = 0.7375 +0x2C3C, // Index: 609 Fraction: 45/61 = 0.7377 +0x1E29, // Index: 610 Fraction: 31/42 = 0.7381 +0x2F40, // Index: 611 Fraction: 48/65 = 0.7385 +0x4057, // Index: 612 Fraction: 65/88 = 0.7386 +0x1016, // Index: 613 Fraction: 17/23 = 0.7391 +0x3548, // Index: 614 Fraction: 54/73 = 0.7397 +0x2431, // Index: 615 Fraction: 37/50 = 0.7400 +0x384C, // Index: 616 Fraction: 57/77 = 0.7403 +0x131A, // Index: 617 Fraction: 20/27 = 0.7407 +0x3E54, // Index: 618 Fraction: 63/85 = 0.7412 +0x2A39, // Index: 619 Fraction: 43/58 = 0.7414 +0x4158, // Index: 620 Fraction: 66/89 = 0.7416 +0x161E, // Index: 621 Fraction: 23/31 = 0.7419 +0x3041, // Index: 622 Fraction: 49/66 = 0.7424 +0x1922, // Index: 623 Fraction: 26/35 = 0.7429 +0x3649, // Index: 624 Fraction: 55/74 = 0.7432 +0x1C26, // Index: 625 Fraction: 29/39 = 0.7436 +0x3C51, // Index: 626 Fraction: 61/82 = 0.7439 +0x1F2A, // Index: 627 Fraction: 32/43 = 0.7442 +0x4259, // Index: 628 Fraction: 67/90 = 0.7444 +0x222E, // Index: 629 Fraction: 35/47 = 0.7447 +0x2532, // Index: 630 Fraction: 38/51 = 0.7451 +0x2836, // Index: 631 Fraction: 41/55 = 0.7455 +0x2B3A, // Index: 632 Fraction: 44/59 = 0.7458 +0x2E3E, // Index: 633 Fraction: 47/63 = 0.7460 +0x3142, // Index: 634 Fraction: 50/67 = 0.7463 +0x3446, // Index: 635 Fraction: 53/71 = 0.7465 +0x374A, // Index: 636 Fraction: 56/75 = 0.7467 +0x3A4E, // Index: 637 Fraction: 59/79 = 0.7468 +0x3D52, // Index: 638 Fraction: 62/83 = 0.7470 +0x4056, // Index: 639 Fraction: 65/87 = 0.7471 +0x0203, // Index: 640 Fraction: 3/4 = 0.7500 +0x4258, // Index: 641 Fraction: 67/89 = 0.7528 +0x3F54, // Index: 642 Fraction: 64/85 = 0.7529 +0x3C50, // Index: 643 Fraction: 61/81 = 0.7531 +0x394C, // Index: 644 Fraction: 58/77 = 0.7532 +0x3648, // Index: 645 Fraction: 55/73 = 0.7534 +0x3344, // Index: 646 Fraction: 52/69 = 0.7536 +0x3040, // Index: 647 Fraction: 49/65 = 0.7538 +0x2D3C, // Index: 648 Fraction: 46/61 = 0.7541 +0x2A38, // Index: 649 Fraction: 43/57 = 0.7544 +0x2734, // Index: 650 Fraction: 40/53 = 0.7547 +0x2430, // Index: 651 Fraction: 37/49 = 0.7551 +0x212C, // Index: 652 Fraction: 34/45 = 0.7556 +0x4055, // Index: 653 Fraction: 65/86 = 0.7558 +0x1E28, // Index: 654 Fraction: 31/41 = 0.7561 +0x3A4D, // Index: 655 Fraction: 59/78 = 0.7564 +0x1B24, // Index: 656 Fraction: 28/37 = 0.7568 +0x3445, // Index: 657 Fraction: 53/70 = 0.7571 +0x1820, // Index: 658 Fraction: 25/33 = 0.7576 +0x2E3D, // Index: 659 Fraction: 47/62 = 0.7581 +0x151C, // Index: 660 Fraction: 22/29 = 0.7586 +0x3E52, // Index: 661 Fraction: 63/83 = 0.7590 +0x2835, // Index: 662 Fraction: 41/54 = 0.7593 +0x3B4E, // Index: 663 Fraction: 60/79 = 0.7595 +0x1218, // Index: 664 Fraction: 19/25 = 0.7600 +0x3546, // Index: 665 Fraction: 54/71 = 0.7606 +0x222D, // Index: 666 Fraction: 35/46 = 0.7609 +0x3242, // Index: 667 Fraction: 51/67 = 0.7612 +0x4257, // Index: 668 Fraction: 67/88 = 0.7614 +0x0F14, // Index: 669 Fraction: 16/21 = 0.7619 +0x3C4F, // Index: 670 Fraction: 61/80 = 0.7625 +0x2C3A, // Index: 671 Fraction: 45/59 = 0.7627 +0x1C25, // Index: 672 Fraction: 29/38 = 0.7632 +0x2936, // Index: 673 Fraction: 42/55 = 0.7636 +0x3647, // Index: 674 Fraction: 55/72 = 0.7639 +0x4358, // Index: 675 Fraction: 68/89 = 0.7640 +0x0C10, // Index: 676 Fraction: 13/17 = 0.7647 +0x3D50, // Index: 677 Fraction: 62/81 = 0.7654 +0x303F, // Index: 678 Fraction: 49/64 = 0.7656 +0x232E, // Index: 679 Fraction: 36/47 = 0.7660 +0x3A4C, // Index: 680 Fraction: 59/77 = 0.7662 +0x161D, // Index: 681 Fraction: 23/30 = 0.7667 +0x3748, // Index: 682 Fraction: 56/73 = 0.7671 +0x202A, // Index: 683 Fraction: 33/43 = 0.7674 +0x2A37, // Index: 684 Fraction: 43/56 = 0.7679 +0x3444, // Index: 685 Fraction: 53/69 = 0.7681 +0x3E51, // Index: 686 Fraction: 63/82 = 0.7683 +0x090C, // Index: 687 Fraction: 10/13 = 0.7692 +0x4256, // Index: 688 Fraction: 67/87 = 0.7701 +0x3849, // Index: 689 Fraction: 57/74 = 0.7703 +0x2E3C, // Index: 690 Fraction: 47/61 = 0.7705 +0x242F, // Index: 691 Fraction: 37/48 = 0.7708 +0x3F52, // Index: 692 Fraction: 64/83 = 0.7711 +0x1A22, // Index: 693 Fraction: 27/35 = 0.7714 +0x2B38, // Index: 694 Fraction: 44/57 = 0.7719 +0x3C4E, // Index: 695 Fraction: 61/79 = 0.7722 +0x1015, // Index: 696 Fraction: 17/22 = 0.7727 +0x394A, // Index: 697 Fraction: 58/75 = 0.7733 +0x2834, // Index: 698 Fraction: 41/53 = 0.7736 +0x4053, // Index: 699 Fraction: 65/84 = 0.7738 +0x171E, // Index: 700 Fraction: 24/31 = 0.7742 +0x3646, // Index: 701 Fraction: 55/71 = 0.7746 +0x1E27, // Index: 702 Fraction: 31/40 = 0.7750 +0x4458, // Index: 703 Fraction: 69/89 = 0.7753 +0x2530, // Index: 704 Fraction: 38/49 = 0.7755 +0x2C39, // Index: 705 Fraction: 45/58 = 0.7759 +0x3342, // Index: 706 Fraction: 52/67 = 0.7761 +0x3A4B, // Index: 707 Fraction: 59/76 = 0.7763 +0x4154, // Index: 708 Fraction: 66/85 = 0.7765 +0x0608, // Index: 709 Fraction: 7/9 = 0.7778 +0x4255, // Index: 710 Fraction: 67/86 = 0.7791 +0x3B4C, // Index: 711 Fraction: 60/77 = 0.7792 +0x3443, // Index: 712 Fraction: 53/68 = 0.7794 +0x2D3A, // Index: 713 Fraction: 46/59 = 0.7797 +0x2631, // Index: 714 Fraction: 39/50 = 0.7800 +0x1F28, // Index: 715 Fraction: 32/41 = 0.7805 +0x3848, // Index: 716 Fraction: 57/73 = 0.7808 +0x181F, // Index: 717 Fraction: 25/32 = 0.7812 +0x4356, // Index: 718 Fraction: 68/87 = 0.7816 +0x2A36, // Index: 719 Fraction: 43/55 = 0.7818 +0x3C4D, // Index: 720 Fraction: 61/78 = 0.7821 +0x1116, // Index: 721 Fraction: 18/23 = 0.7826 +0x4052, // Index: 722 Fraction: 65/83 = 0.7831 +0x2E3B, // Index: 723 Fraction: 47/60 = 0.7833 +0x1C24, // Index: 724 Fraction: 29/37 = 0.7838 +0x4457, // Index: 725 Fraction: 69/88 = 0.7841 +0x2732, // Index: 726 Fraction: 40/51 = 0.7843 +0x3240, // Index: 727 Fraction: 51/65 = 0.7846 +0x3D4E, // Index: 728 Fraction: 62/79 = 0.7848 +0x0A0D, // Index: 729 Fraction: 11/14 = 0.7857 +0x4558, // Index: 730 Fraction: 70/89 = 0.7865 +0x3A4A, // Index: 731 Fraction: 59/75 = 0.7867 +0x2F3C, // Index: 732 Fraction: 48/61 = 0.7869 +0x242E, // Index: 733 Fraction: 37/47 = 0.7872 +0x3E4F, // Index: 734 Fraction: 63/80 = 0.7875 +0x1920, // Index: 735 Fraction: 26/33 = 0.7879 +0x4254, // Index: 736 Fraction: 67/85 = 0.7882 +0x2833, // Index: 737 Fraction: 41/52 = 0.7885 +0x3746, // Index: 738 Fraction: 56/71 = 0.7887 +0x4659, // Index: 739 Fraction: 71/90 = 0.7889 +0x0E12, // Index: 740 Fraction: 15/19 = 0.7895 +0x3F50, // Index: 741 Fraction: 64/81 = 0.7901 +0x303D, // Index: 742 Fraction: 49/62 = 0.7903 +0x212A, // Index: 743 Fraction: 34/43 = 0.7907 +0x3442, // Index: 744 Fraction: 53/67 = 0.7910 +0x1217, // Index: 745 Fraction: 19/24 = 0.7917 +0x3C4C, // Index: 746 Fraction: 61/77 = 0.7922 +0x2934, // Index: 747 Fraction: 42/53 = 0.7925 +0x4051, // Index: 748 Fraction: 65/82 = 0.7927 +0x161C, // Index: 749 Fraction: 23/29 = 0.7931 +0x313E, // Index: 750 Fraction: 50/63 = 0.7937 +0x1A21, // Index: 751 Fraction: 27/34 = 0.7941 +0x3948, // Index: 752 Fraction: 58/73 = 0.7945 +0x1E26, // Index: 753 Fraction: 31/39 = 0.7949 +0x4152, // Index: 754 Fraction: 66/83 = 0.7952 +0x222B, // Index: 755 Fraction: 35/44 = 0.7955 +0x2630, // Index: 756 Fraction: 39/49 = 0.7959 +0x2A35, // Index: 757 Fraction: 43/54 = 0.7963 +0x2E3A, // Index: 758 Fraction: 47/59 = 0.7966 +0x323F, // Index: 759 Fraction: 51/64 = 0.7969 +0x3644, // Index: 760 Fraction: 55/69 = 0.7971 +0x3A49, // Index: 761 Fraction: 59/74 = 0.7973 +0x3E4E, // Index: 762 Fraction: 63/79 = 0.7975 +0x4253, // Index: 763 Fraction: 67/84 = 0.7976 +0x4658, // Index: 764 Fraction: 71/89 = 0.7978 +0x0304, // Index: 765 Fraction: 4/5 = 0.8000 +0x4455, // Index: 766 Fraction: 69/86 = 0.8023 +0x4050, // Index: 767 Fraction: 65/81 = 0.8025 +0x3C4B, // Index: 768 Fraction: 61/76 = 0.8026 +0x3846, // Index: 769 Fraction: 57/71 = 0.8028 +0x3441, // Index: 770 Fraction: 53/66 = 0.8030 +0x303C, // Index: 771 Fraction: 49/61 = 0.8033 +0x2C37, // Index: 772 Fraction: 45/56 = 0.8036 +0x2832, // Index: 773 Fraction: 41/51 = 0.8039 +0x242D, // Index: 774 Fraction: 37/46 = 0.8043 +0x4556, // Index: 775 Fraction: 70/87 = 0.8046 +0x2028, // Index: 776 Fraction: 33/41 = 0.8049 +0x3D4C, // Index: 777 Fraction: 62/77 = 0.8052 +0x1C23, // Index: 778 Fraction: 29/36 = 0.8056 +0x3542, // Index: 779 Fraction: 54/67 = 0.8060 +0x181E, // Index: 780 Fraction: 25/31 = 0.8065 +0x4657, // Index: 781 Fraction: 71/88 = 0.8068 +0x2D38, // Index: 782 Fraction: 46/57 = 0.8070 +0x4252, // Index: 783 Fraction: 67/83 = 0.8072 +0x1419, // Index: 784 Fraction: 21/26 = 0.8077 +0x3A48, // Index: 785 Fraction: 59/73 = 0.8082 +0x252E, // Index: 786 Fraction: 38/47 = 0.8085 +0x3643, // Index: 787 Fraction: 55/68 = 0.8088 +0x4758, // Index: 788 Fraction: 72/89 = 0.8090 +0x1014, // Index: 789 Fraction: 17/21 = 0.8095 +}; diff --git a/examples/ffd/src/i2c_reg_handling.c b/examples/ffd/src/i2c_reg_handling.c new file mode 100644 index 000000000..9029d6331 --- /dev/null +++ b/examples/ffd/src/i2c_reg_handling.c @@ -0,0 +1,41 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include "i2c_reg_handling.h" + +/** + * @brief Minimum length for a write request. + */ +#define WRITE_REQUEST_MIN_LEN 1 + +RTOS_I2C_SLAVE_CALLBACK_ATTR +size_t read_device_reg(rtos_i2c_slave_t *ctx, + asr_result_t *last_asr_result, + uint8_t **data) +{ +#if appconfINTENT_I2C_SLAVE_POLLED_ENABLED==1 + uint8_t * data_p = *data; + uint8_t reg_addr = data_p[0]; + uint8_t reg_value = 0xFF; + if (reg_addr == appconfINTENT_I2C_REG_ADDRESS) { + reg_value = last_asr_result->id; + } + data_p[0] = reg_value; + rtos_printf("Read from register 0x%02X value 0x%02X\n", reg_addr, reg_value); +#endif + return 1; +} + +RTOS_I2C_SLAVE_CALLBACK_ATTR +void write_device_reg(rtos_i2c_slave_t *ctx, + void *app_data, + uint8_t *data, + size_t len) +{ +#if appconfINTENT_I2C_SLAVE_POLLED_ENABLED==1 + // If the length is lower than WRITE_REQUEST_MIN_LEN, it is a read request + if (len > WRITE_REQUEST_MIN_LEN) { + rtos_printf("Write to register 0x%02X value 0x%02X (len %d)\n", data[0], data[1], len); + } +#endif +} diff --git a/examples/ffd/src/i2c_reg_handling.h b/examples/ffd/src/i2c_reg_handling.h new file mode 100644 index 000000000..449b13de6 --- /dev/null +++ b/examples/ffd/src/i2c_reg_handling.h @@ -0,0 +1,36 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include "rtos_i2c_slave.h" +#include "app_conf.h" +#include "asr.h" + +/** + * Callback for reading data from a device register over I2C slave. + * Only one byte of data is read from the register. + * + * @param ctx Pointer to the I2C slave context. + * @param last_asr_result Pointer to the last Automatic Speech Recognition (ASR) result. + * @param data Pointer to a pointer to the the data to be sent to the master device. + * + * @return The size of the data read. + */ +RTOS_I2C_SLAVE_CALLBACK_ATTR +size_t read_device_reg(rtos_i2c_slave_t *ctx, + asr_result_t *last_asr_result, + uint8_t **data); + +/** + * Callback for writing data to a device register over I2C slave. + * Only one byte of data is written to the register. + * + * @param ctx Pointer to the I2C slave context. + * @param app_data Pointer to application-specific data. Not used. + * @param data Pointer to the the data received from the master device. + * @param len The length of the data to be written. + */ +RTOS_I2C_SLAVE_CALLBACK_ATTR +void write_device_reg(rtos_i2c_slave_t *ctx, + void *app_data, + uint8_t *data, + size_t len); diff --git a/examples/ffd/src/main.c b/examples/ffd/src/main.c index 043ce6240..028bb7c09 100644 --- a/examples/ffd/src/main.c +++ b/examples/ffd/src/main.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* System headers */ @@ -28,10 +28,64 @@ #include "gpio_ctrl/leds.h" #include "intent_handler/intent_handler.h" +#if appconfI2S_ENABLED +#include "src.h" +#endif + +#if appconfRECOVER_MCLK_I2S_APP_PLL +/* Config headers for sw_pll */ +#include "sw_pll.h" +#endif + #ifndef MEM_ANALYSIS_ENABLED #define MEM_ANALYSIS_ENABLED 0 #endif +#if appconfI2S_ENABLED && (appconfI2S_MODE == appconfI2S_MODE_SLAVE) +void i2s_slave_intertile() +{ + int32_t tmp[appconfAUDIO_PIPELINE_FRAME_ADVANCE][appconfAUDIO_PIPELINE_CHANNELS]; + while(1) { + memset(tmp, 0x00, sizeof(tmp)); + + size_t bytes_received = 0; + bytes_received = rtos_intertile_rx_len( + intertile_ctx, + appconfI2S_OUTPUT_SLAVE_PORT, + portMAX_DELAY); + + xassert(bytes_received == sizeof(tmp)); + + rtos_intertile_rx_data( + intertile_ctx, + tmp, + bytes_received); + + rtos_i2s_tx(i2s_ctx, + (int32_t*) tmp, + appconfAUDIO_PIPELINE_FRAME_ADVANCE, + portMAX_DELAY); + } +} +#endif + +#if appconfRECOVER_MCLK_I2S_APP_PLL +void sw_pll_control(void *args) +{ + + while(1) + { + sw_pll_ctx_t* i2s_callback_args = (sw_pll_ctx_t*) args; + port_clear_buffer(i2s_callback_args->p_bclk_count); + port_in(i2s_callback_args->p_bclk_count); // Block until BCLK transition to synchronise. Will consume up to 1/64 of a LRCLK cycle + uint16_t mclk_pt = port_get_trigger_time(i2s_callback_args->p_mclk_count); // Immediately sample mclk_count + uint16_t bclk_pt = port_get_trigger_time(i2s_callback_args->p_bclk_count); // Now grab bclk_count (which won't have changed) + + sw_pll_lut_do_control(i2s_callback_args->sw_pll, mclk_pt, bclk_pt); + } +} +#endif + void audio_pipeline_input(void *input_app_data, int32_t **input_audio_frames, size_t ch_count, @@ -39,6 +93,7 @@ void audio_pipeline_input(void *input_app_data, { (void) input_app_data; +#if !appconfUSE_I2S_INPUT static int flushed; while (!flushed) { size_t received; @@ -59,6 +114,26 @@ void audio_pipeline_input(void *input_app_data, input_audio_frames, frame_count, portMAX_DELAY); + +#else + xassert(frame_count == appconfAUDIO_PIPELINE_FRAME_ADVANCE); + int32_t tmp[appconfAUDIO_PIPELINE_FRAME_ADVANCE][appconfAUDIO_PIPELINE_CHANNELS]; + int32_t *tmpptr = (int32_t *)input_audio_frames; + + /* I2S provides sample channel format */ + size_t rx_count = + rtos_i2s_rx(i2s_ctx, + (int32_t *) tmp, + frame_count, + portMAX_DELAY); + + + for (int i=0; i= 2) { + i2s_frame[0] = src_us3_voice_input_sample(src_data[0], src_ff3v_fir_coefs[2], send_buf[0]); + i2s_frame[1] = src_us3_voice_input_sample(src_data[1], src_ff3v_fir_coefs[2], send_buf[1]); + return 2; + } else { + i2s_frame[0] = src_us3_voice_input_sample(src_data[0], src_ff3v_fir_coefs[2], 0); + i2s_frame[1] = src_us3_voice_input_sample(src_data[1], src_ff3v_fir_coefs[2], 0); + return 0; + } + case 1: + i = 2; + i2s_frame[0] = src_us3_voice_get_next_sample(src_data[0], src_ff3v_fir_coefs[1]); + i2s_frame[1] = src_us3_voice_get_next_sample(src_data[1], src_ff3v_fir_coefs[1]); + return 0; + case 2: + i = 0; + i2s_frame[0] = src_us3_voice_get_next_sample(src_data[0], src_ff3v_fir_coefs[0]); + i2s_frame[1] = src_us3_voice_get_next_sample(src_data[1], src_ff3v_fir_coefs[0]); + return 0; + default: + xassert(0); + return 0; + } +} + +RTOS_I2S_APP_RECEIVE_FILTER_CALLBACK_ATTR +size_t i2s_send_downsample_cb(rtos_i2s_t *ctx, void *app_data, int32_t *i2s_frame, size_t i2s_frame_size, int32_t *receive_buf, size_t sample_spaces_free) +{ + static int i; + static int64_t sum[2]; + static int32_t src_data[2][SRC_FF3V_FIR_NUM_PHASES][SRC_FF3V_FIR_TAPS_PER_PHASE] __attribute__((aligned (8))); + + xassert(i2s_frame_size == 2); + + switch (i) { + case 0: + i = 1; + sum[0] = src_ds3_voice_add_sample(0, src_data[0][0], src_ff3v_fir_coefs[0], i2s_frame[0]); + sum[1] = src_ds3_voice_add_sample(0, src_data[1][0], src_ff3v_fir_coefs[0], i2s_frame[1]); + return 0; + case 1: + i = 2; + sum[0] = src_ds3_voice_add_sample(sum[0], src_data[0][1], src_ff3v_fir_coefs[1], i2s_frame[0]); + sum[1] = src_ds3_voice_add_sample(sum[1], src_data[1][1], src_ff3v_fir_coefs[1], i2s_frame[1]); + return 0; + case 2: + i = 0; + if (sample_spaces_free >= 2) { + receive_buf[0] = src_ds3_voice_add_final_sample(sum[0], src_data[0][2], src_ff3v_fir_coefs[2], i2s_frame[0]); + receive_buf[1] = src_ds3_voice_add_final_sample(sum[1], src_data[1][2], src_ff3v_fir_coefs[2], i2s_frame[1]); + return 2; + } else { + (void) src_ds3_voice_add_final_sample(sum[0], src_data[0][2], src_ff3v_fir_coefs[2], i2s_frame[0]); + (void) src_ds3_voice_add_final_sample(sum[1], src_data[1][2], src_ff3v_fir_coefs[2], i2s_frame[1]); + return 0; + } + default: + xassert(0); + return 0; + } +} + +void i2s_rate_conversion_enable(void) +{ +#if !appconfI2S_TDM_ENABLED + rtos_i2s_send_filter_cb_set(i2s_ctx, i2s_send_upsample_cb, NULL); +#endif + rtos_i2s_receive_filter_cb_set(i2s_ctx, i2s_send_downsample_cb, NULL); +} +#endif // appconfUSE_I2S_INPUT void vApplicationMallocFailedHook(void) { @@ -96,6 +253,24 @@ void startup_task(void *arg) platform_start(); +#if ON_TILE(I2S_TILE_NO) && appconfI2S_ENABLED && (appconfI2S_MODE == appconfI2S_MODE_SLAVE) + + xTaskCreate((TaskFunction_t) i2s_slave_intertile, + "i2s_slave_intertile", + RTOS_THREAD_STACK_SIZE(i2s_slave_intertile), + NULL, + appconfAUDIO_PIPELINE_TASK_PRIORITY, + NULL); +#if appconfRECOVER_MCLK_I2S_APP_PLL + xTaskCreate((TaskFunction_t) sw_pll_control, + "sw_pll_control", + RTOS_THREAD_STACK_SIZE(sw_pll_control), + sw_pll_ctx, + appconfAUDIO_PIPELINE_TASK_PRIORITY, + NULL); +#endif +#endif + #if ON_TILE(0) led_task_create(appconfLED_TASK_PRIORITY, NULL); #endif @@ -117,7 +292,7 @@ void startup_task(void *arg) intent_engine_create(appconfINTENT_MODEL_RUNNER_TASK_PRIORITY, q_intent); #endif -#if ON_TILE(AUDIO_PIPELINE_TILE_NO) +#if ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) #if appconfINTENT_ENABLED // Wait until the intent engine is initialized before starting the // audio pipeline. diff --git a/examples/ffd/src/register_setup_1000ppm.h b/examples/ffd/src/register_setup_1000ppm.h new file mode 100644 index 000000000..25646bcd7 --- /dev/null +++ b/examples/ffd/src/register_setup_1000ppm.h @@ -0,0 +1,17 @@ +// Copyright 2023-2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +/* Autogenerated by sw_pll_sim.py using command: + /Users/ed/sandboxes/sw_xvf3800/lib_sw_pll/python/sw_pll/pll_calc.py -i 24.0 -a -m 90 -t 12.288 -p 6.0 -e 5 -r --fracmin 0.49 --fracmax 0.81 --header + Picked output solution #83 + F: 154 + R: 1 + f: 56 + p: 87 + OD: 1 + ACD: 18 + Output freq: 12287978.0 + VCO freq: 1867770000.0 */ + +#define APP_PLL_CTL_REG 0x08809A01 +#define APP_PLL_DIV_REG 0x80000012 +#define APP_PLL_FRAC_REG 0x80003857 diff --git a/examples/ffva/README.rst b/examples/ffva/README.rst index 4a9c0760e..a4f84b247 100644 --- a/examples/ffva/README.rst +++ b/examples/ffva/README.rst @@ -9,21 +9,11 @@ Supported Hardware and pre-requisites This example is supported on the XK_VOICE_L71 board. -On the host machine the XTC tools, version 15.2.1, must be installed and sourced. -The output should be -something like this: +Make sure that your XTC tools environment is activated. -:: - - $ xcc --version - xcc: Build 19-198606c, Oct-25-2022 - XTC version: 15.2.1 - Copyright (C) XMOS Limited 2008-2021. All Rights Reserved. - -On Windows it is highly recommended to use ``Ninja`` as the make system under -``cmake``. Not only is it a lot faster than MSVC ``nmake``, it also -works around an issue where certain path names may cause an issue with -the XMOS compiler under Windows. +It is recommended to use `Ninja` or `xmake` as the make system under Windows. +`Ninja` has been observed to be faster than `xmake`, however `xmake` comes natively with XTC tools. +This firmware has been tested with `Ninja` version v1.11.1. To install Ninja, follow these steps: @@ -78,27 +68,31 @@ The host applications will be installed at ``%USERPROFILE%\.xmos\bin``, and may Building the Firmware ===================== -Run the following commands in the root folder to build the firmware. +After having your python environment activated, run the following commands in the root folder to build the firmware: On Linux and Mac run: :: + pip install -r requirements.txt cmake -B build --toolchain xmos_cmake_toolchain/xs3a.cmake cd build - make example_ffva_int_fixed_delay make example_ffva_ua_adec_altarch + make example_ffva_int_fixed_delay + make example_ffva_int_cyberon_fixed_delay On Windows run: :: + pip install -r requirements.txt cmake -G Ninja -B build --toolchain xmos_cmake_toolchain/xs3a.cmake cd build - ninja example_ffva_int_fixed_delay ninja example_ffva_ua_adec_altarch + ninja example_ffva_int_fixed_delay + ninja example_ffva_int_cyberon_fixed_delay From the build folder, create the data partition containing the filesystem and flash the device with the appropriate command to the desired configuration: @@ -107,15 +101,17 @@ On Linux and Mac run: :: - make flash_app_example_ffva_int_fixed_delay make flash_app_example_ffva_ua_adec_altarch + make flash_app_example_ffva_int_fixed_delay + make flash_app_example_ffva_int_cyberon_fixed_delay On Windows run: :: - ninja flash_app_example_ffva_int_fixed_delay ninja flash_app_example_ffva_ua_adec_altarch + ninja flash_app_example_ffva_int_fixed_delay + ninja flash_app_example_ffva_int_cyberon_fixed_delay Once flashed, the application will run. @@ -129,8 +125,10 @@ Run the following commands in the build folder: :: - xrun --xscope example_ffva_int_fixed_delay.xe xrun --xscope example_ffva_ua_adec_altarch.xe + xrun --xscope example_ffva_int_fixed_delay.xe + xrun --xscope example_ffva_int_cyberon_fixed_delay.xe + Debugging the firmware with `xgdb` ================================= @@ -139,8 +137,10 @@ Run the following commands in the build folder: :: - xgdb -ex "conn --xscope" -ex "r" example_ffva_int_fixed_delay.xe xgdb -ex "conn --xscope" -ex "r" example_ffva_ua_adec_altarch.xe + xgdb -ex "conn --xscope" -ex "r" example_ffva_int_fixed_delay.xe + xgdb -ex "conn --xscope" -ex "r" example_ffva_int_cyberon_fixed_delay.xe + Running the Firmware With WAV Files =================================== @@ -149,12 +149,13 @@ This application supports USB audio input and output debug configuration. To enable USB audio debug, configure cmake with: -Run the following commands in the root folder to build the firmware. +After having your python environment activated, run the following commands in the root folder to build the firmware: On Linux and Mac run:: :: + pip install -r requirements.txt cmake -B build --toolchain xmos_cmake_toolchain/xs3a.cmake -DDEBUG_FFVA_USB_MIC_INPUT=1 cd build @@ -164,6 +165,7 @@ On Windows run: :: + pip install -r requirements.txt cmake -G Ninja -B build --toolchain xmos_cmake_toolchain/xs3a.cmake -DDEBUG_FFVA_USB_MIC_INPUT=1 cd build diff --git a/examples/ffva/asr/model/english_usa/Hello_XMOS_pack_WithTxt.bin.Enc.NibbleSwap b/examples/ffva/asr/model/english_usa/Hello_XMOS_pack_WithTxt.bin.Enc.NibbleSwap new file mode 100644 index 000000000..5cc86af72 Binary files /dev/null and b/examples/ffva/asr/model/english_usa/Hello_XMOS_pack_WithTxt.bin.Enc.NibbleSwap differ diff --git a/examples/ffva/bsp_config/XCORE-AI-EXPLORER/XCORE-AI-EXPLORER.xn b/examples/ffva/bsp_config/XCORE-AI-EXPLORER/XCORE-AI-EXPLORER.xn index 754092ece..839a29741 100644 --- a/examples/ffva/bsp_config/XCORE-AI-EXPLORER/XCORE-AI-EXPLORER.xn +++ b/examples/ffva/bsp_config/XCORE-AI-EXPLORER/XCORE-AI-EXPLORER.xn @@ -74,7 +74,7 @@ - + @@ -97,12 +97,10 @@ - + - - diff --git a/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_conf.h b/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_conf.h index b1b3ea35c..bfece44f8 100644 --- a/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_conf.h +++ b/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_conf.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef PLATFORM_CONF_H_ @@ -101,21 +101,21 @@ #define appconfPIPELINE_AUDIO_SAMPLE_RATE 16000 #endif /* appconfPIPELINE_AUDIO_SAMPLE_RATE */ -#ifndef appconfI2C_CTRL_ENABLED -#define appconfI2C_CTRL_ENABLED 0 -#endif /* appconfI2C_CTRL_ENABLED */ +#ifndef appconfI2C_DFU_ENABLED +#define appconfI2C_DFU_ENABLED 0 +#endif /* appconfI2C_DFU_ENABLED */ + +#ifndef APP_CONTROL_TRANSPORT_COUNT +#define APP_CONTROL_TRANSPORT_COUNT appconfI2C_DFU_ENABLED +#endif // APP_CONTROL_TRANSPORT_COUNT #ifndef appconfEXTERNAL_MCLK -#if appconfI2C_CTRL_ENABLED #define appconfEXTERNAL_MCLK 1 -#else -#define appconfEXTERNAL_MCLK 0 -#endif /* appconfI2C_CTRL_ENABLED */ #endif /* appconfEXTERNAL_MCLK */ -#ifndef appconf_CONTROL_I2C_DEVICE_ADDR -#define appconf_CONTROL_I2C_DEVICE_ADDR 0x42 -#endif /* appconf_CONTROL_I2C_DEVICE_ADDR*/ +#ifndef appconfI2C_SLAVE_DEVICE_ADDR +#define appconfI2C_SLAVE_DEVICE_ADDR 0x42 +#endif /* appconfI2C_SLAVE_DEVICE_ADDR*/ #ifndef appconfSPI_OUTPUT_ENABLED #define appconfSPI_OUTPUT_ENABLED 0 @@ -188,14 +188,14 @@ #ifndef BOARD_QSPI_SPEC /* Set up a default SPI spec if the app has not provided * one explicitly. - * Note: The version checks only work in XTC Tools >15.2.0 - * By default FL_QUADDEVICE_W25Q64JW is used + * Note: The version checks only work in XTC Tools >15.2.0 + * By default FL_QUADDEVICE_W25Q64JW is used */ #ifdef __XMOS_XTC_VERSION_MAJOR__ #if (__XMOS_XTC_VERSION_MAJOR__ == 15) \ && (__XMOS_XTC_VERSION_MINOR__ >= 2) \ && (__XMOS_XTC_VERSION_PATCH__ >= 0) -/* In XTC >15.2.0 some SFDP support enables a generic +/* In XTC >15.2.0 some SFDP support enables a generic * default spec */ #define BOARD_QSPI_SPEC FL_QUADDEVICE_DEFAULT diff --git a/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_init.c b/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_init.c index a2650e0bf..84724f174 100644 --- a/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_init.c +++ b/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_init.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* System headers */ @@ -14,7 +14,7 @@ static void mclk_init(chanend_t other_tile_c) { -#if ON_TILE(1) && !appconfEXTERNAL_MCLK +#if ON_TILE(I2S_TILE_NO) && !appconfEXTERNAL_MCLK app_pll_init(); #endif #if appconfUSB_ENABLED && ON_TILE(USB_TILE_NO) @@ -88,13 +88,13 @@ static void gpio_init(void) static void i2c_init(void) { -#if appconfI2C_CTRL_ENABLED +#if appconfI2C_DFU_ENABLED #if ON_TILE(I2C_CTRL_TILE_NO) rtos_i2c_slave_init(i2c_slave_ctx, (1 << appconfI2C_IO_CORE), PORT_I2C_SLAVE_SCL, PORT_I2C_SLAVE_SDA, - appconf_CONTROL_I2C_DEVICE_ADDR); + appconfI2C_SLAVE_DEVICE_ADDR); #endif #else static rtos_driver_rpc_t i2c_rpc_config; diff --git a/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_start.c b/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_start.c index 1bb8729a0..8b548ad24 100644 --- a/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_start.c +++ b/examples/ffva/bsp_config/XCORE-AI-EXPLORER/platform/platform_start.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* System headers */ @@ -16,8 +16,7 @@ #include "aic3204.h" #include "usb_support.h" -#if appconfI2C_CTRL_ENABLED -#include "app_control/app_control.h" +#if appconfI2C_DFU_ENABLED #include "device_control_i2c.h" #endif @@ -47,7 +46,7 @@ static void flash_start(void) static void i2c_master_start(void) { -#if !appconfI2C_CTRL_ENABLED +#if !appconfI2C_DFU_ENABLED rtos_i2c_master_rpc_config(i2c_master_ctx, appconfI2C_MASTER_RPC_PORT, appconfI2C_MASTER_RPC_PRIORITY); #if ON_TILE(I2C_TILE_NO) @@ -58,7 +57,7 @@ static void i2c_master_start(void) static void audio_codec_start(void) { -#if !appconfI2C_CTRL_ENABLED +#if !appconfI2C_DFU_ENABLED #if appconfI2S_ENABLED int ret = 0; #if ON_TILE(I2C_TILE_NO) @@ -76,7 +75,7 @@ static void audio_codec_start(void) static void i2c_slave_start(void) { -#if appconfI2C_CTRL_ENABLED && ON_TILE(I2C_CTRL_TILE_NO) +#if appconfI2C_DFU_ENABLED && ON_TILE(I2C_CTRL_TILE_NO) rtos_i2c_slave_start(i2c_slave_ctx, device_control_i2c_ctx, (rtos_i2c_slave_start_cb_t) device_control_i2c_start_cb, @@ -124,7 +123,7 @@ static void mics_start(void) static void i2s_start(void) { #if appconfI2S_ENABLED - rtos_i2s_rpc_config(i2s_ctx, appconfI2S_RPC_PORT, appconfI2S_RPC_PRIORITY); + rtos_i2s_rpc_config(i2s_ctx, appconfI2S_RPC_PORT, appconfI2S_RPC_PRIORITY); #if ON_TILE(I2S_TILE_NO) if (appconfI2S_AUDIO_SAMPLE_RATE == 3*appconfAUDIO_PIPELINE_SAMPLE_RATE) { diff --git a/examples/ffva/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn b/examples/ffva/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn index b927e064e..44199fd44 100644 --- a/examples/ffva/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn +++ b/examples/ffva/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn @@ -56,6 +56,10 @@ + + + + @@ -77,12 +81,10 @@ - + - - diff --git a/examples/ffva/bsp_config/XK_VOICE_L71/platform/dac_port.c b/examples/ffva/bsp_config/XK_VOICE_L71/platform/dac_port.c index 1c72c4f3a..e3bda5f19 100644 --- a/examples/ffva/bsp_config/XK_VOICE_L71/platform/dac_port.c +++ b/examples/ffva/bsp_config/XK_VOICE_L71/platform/dac_port.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* System headers */ @@ -13,7 +13,7 @@ #include "dac3101.h" #include "pcal6408a.h" -/* I2C io expander address on XCF3610_Q60A board */ +/* I2C io expander address on XK-VOICE-L71 board */ #define IOEXP_I2C_ADDR PCAL6408A_I2C_ADDR /* IO expander pinout */ diff --git a/examples/ffva/bsp_config/XK_VOICE_L71/platform/driver_instances.c b/examples/ffva/bsp_config/XK_VOICE_L71/platform/driver_instances.c index e7265da07..106899db0 100644 --- a/examples/ffva/bsp_config/XK_VOICE_L71/platform/driver_instances.c +++ b/examples/ffva/bsp_config/XK_VOICE_L71/platform/driver_instances.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include "platform/driver_instances.h" @@ -35,3 +35,9 @@ rtos_spi_slave_t *spi_slave_ctx = &spi_slave_ctx_s; static rtos_dfu_image_t dfu_image_ctx_s; rtos_dfu_image_t *dfu_image_ctx = &dfu_image_ctx_s; + +static rtos_uart_tx_t uart_tx_ctx_s; +rtos_uart_tx_t *uart_tx_ctx = &uart_tx_ctx_s; + +static sw_pll_ctx_t sw_pll_ctx_s; +sw_pll_ctx_t *sw_pll_ctx = &sw_pll_ctx_s; diff --git a/examples/ffva/bsp_config/XK_VOICE_L71/platform/driver_instances.h b/examples/ffva/bsp_config/XK_VOICE_L71/platform/driver_instances.h index 72abcf376..9e02ae72e 100644 --- a/examples/ffva/bsp_config/XK_VOICE_L71/platform/driver_instances.h +++ b/examples/ffva/bsp_config/XK_VOICE_L71/platform/driver_instances.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef DRIVER_INSTANCES_H_ @@ -13,6 +13,12 @@ #include "rtos_qspi_flash.h" #include "rtos_dfu_image.h" #include "rtos_spi_slave.h" +#include "rtos_uart_tx.h" + +/* Config headers for sw_pll */ +#include "sw_pll.h" +#include "fractions_1000ppm.h" +#include "register_setup_1000ppm.h" /* Tile specifiers */ #define FLASH_TILE_NO 0 @@ -21,6 +27,7 @@ #define SPI_OUTPUT_TILE_NO 0 #define MICARRAY_TILE_NO 1 #define I2S_TILE_NO 1 +#define UART_TILE_NO 0 /** TILE 0 Clock Blocks */ #define FLASH_CLKBLK XS1_CLKBLK_1 @@ -59,5 +66,17 @@ extern rtos_i2c_slave_t *i2c_slave_ctx; extern rtos_spi_slave_t *spi_slave_ctx; extern rtos_i2s_t *i2s_ctx; extern rtos_dfu_image_t *dfu_image_ctx; +extern rtos_uart_tx_t *uart_tx_ctx; + +typedef struct { + port_t p_mclk_count; // Used for keeping track of MCLK output for sw_pll + port_t p_bclk_count; // Used for keeping track of BCLK input for sw_pll + sw_pll_state_t *sw_pll; // Pointer to sw_pll state (if used) + +}sw_pll_ctx_t; + +static sw_pll_state_t sw_pll = {0}; + +extern sw_pll_ctx_t *sw_pll_ctx; #endif /* DRIVER_INSTANCES_H_ */ diff --git a/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_conf.h b/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_conf.h index 56797e2ae..81d68279c 100644 --- a/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_conf.h +++ b/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_conf.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef PLATFORM_CONF_H_ @@ -101,43 +101,37 @@ #define appconfPIPELINE_AUDIO_SAMPLE_RATE 16000 #endif /* appconfPIPELINE_AUDIO_SAMPLE_RATE */ -#ifndef appconfI2C_CTRL_ENABLED +#ifndef appconfI2C_DFU_ENABLED +#if ! ASR_CYBERON /* - * When this is enabled on the XVF3610_Q60A board, the board + * When this is enabled on the XK-VOICE-L71 board, the board * cannot function as an I2C master and will not configure the * DAC. In this case the DAC should be configured externally. * MCLK will also default to be external if this is set on - * the XVF3610_Q60A board. + * the XK-VOICE-L71 board. */ -#define appconfI2C_CTRL_ENABLED 0 -#endif /* appconfI2C_CTRL_ENABLED */ +#define appconfI2C_DFU_ENABLED 1 +#else +#define appconfI2C_DFU_ENABLED 0 +#endif +#endif /* appconfI2C_DFU_ENABLED */ + +#ifndef APP_CONTROL_TRANSPORT_COUNT +#define APP_CONTROL_TRANSPORT_COUNT appconfI2C_DFU_ENABLED +#endif // APP_CONTROL_TRANSPORT_COUNT #ifndef appconfEXTERNAL_MCLK -#if appconfI2C_CTRL_ENABLED #define appconfEXTERNAL_MCLK 1 -#else -#define appconfEXTERNAL_MCLK 0 -#endif /* appconfI2C_CTRL_ENABLED */ #endif /* appconfEXTERNAL_MCLK */ -#ifndef appconf_CONTROL_I2C_DEVICE_ADDR -#define appconf_CONTROL_I2C_DEVICE_ADDR 0x42 -#endif /* appconf_CONTROL_I2C_DEVICE_ADDR*/ +#ifndef appconfI2C_SLAVE_DEVICE_ADDR +#define appconfI2C_SLAVE_DEVICE_ADDR 0x42 +#endif /* appconfI2C_SLAVE_DEVICE_ADDR*/ #ifndef appconfSPI_OUTPUT_ENABLED #define appconfSPI_OUTPUT_ENABLED 0 #endif /* appconfSPI_OUTPUT_ENABLED */ -#ifndef appconfI2S_MODE_MASTER -#define appconfI2S_MODE_MASTER 0 -#endif /* appconfI2S_MODE_MASTER */ -#ifndef appconfI2S_MODE_SLAVE -#define appconfI2S_MODE_SLAVE 1 -#endif /* appconfI2S_MODE_SLAVE */ -#ifndef appconfI2S_MODE -#define appconfI2S_MODE appconfI2S_MODE_MASTER -#endif /* appconfI2S_MODE */ - /* * This option sends all 6 16 KHz channels (two channels of processed audio, * stereo reference audio, and stereo microphone audio) out over a single @@ -151,7 +145,7 @@ /* I/O Task Priorities */ /*****************************************/ #ifndef appconfQSPI_FLASH_TASK_PRIORITY -#define appconfQSPI_FLASH_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define appconfQSPI_FLASH_TASK_PRIORITY (configMAX_PRIORITIES-1) #endif /* appconfQSPI_FLASH_TASK_PRIORITY */ #ifndef appconfI2C_TASK_PRIORITY @@ -162,6 +156,10 @@ #define appconfSPI_TASK_PRIORITY (configMAX_PRIORITIES/2) #endif /* appconfSPI_TASK_PRIORITY */ +#ifndef appconfDEVICE_CONTROL_I2C_PRIORITY +#define appconfDEVICE_CONTROL_I2C_PRIORITY (configMAX_PRIORITIES-1) +#endif // appconfDEVICE_CONTROL_I2C_PRIORITY + /*****************************************/ /* DFU Settings */ /*****************************************/ @@ -195,14 +193,14 @@ #ifndef BOARD_QSPI_SPEC /* Set up a default SPI spec if the app has not provided * one explicitly. - * Note: The version checks only work in XTC Tools >15.2.0 - * By default FL_QUADDEVICE_W25Q64JW is used + * Note: The version checks only work in XTC Tools >15.2.0 + * By default FL_QUADDEVICE_W25Q64JW is used */ #ifdef __XMOS_XTC_VERSION_MAJOR__ #if (__XMOS_XTC_VERSION_MAJOR__ == 15) \ && (__XMOS_XTC_VERSION_MINOR__ >= 2) \ && (__XMOS_XTC_VERSION_PATCH__ >= 0) -/* In XTC >15.2.0 some SFDP support enables a generic +/* In XTC >15.2.0 some SFDP support enables a generic * default spec */ #define BOARD_QSPI_SPEC FL_QUADDEVICE_DEFAULT diff --git a/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_init.c b/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_init.c index e549b2947..8fbb692e6 100644 --- a/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_init.c +++ b/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_init.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* System headers */ @@ -11,10 +11,14 @@ #include "platform/platform_init.h" #include "adaptive_rate_adjust.h" #include "usb_support.h" +#include "device_control.h" +#include "servicer.h" + +extern device_control_t *device_control_i2c_ctx; static void mclk_init(chanend_t other_tile_c) { -#if !appconfEXTERNAL_MCLK && ON_TILE(1) +#if !appconfEXTERNAL_MCLK && ON_TILE(I2S_TILE_NO) app_pll_init(); #endif #if appconfUSB_ENABLED && ON_TILE(USB_TILE_NO) @@ -25,6 +29,21 @@ static void mclk_init(chanend_t other_tile_c) static void flash_init(void) { #if ON_TILE(FLASH_TILE_NO) +// Flash fast read is used for reading the WW model in the INT device, +// normal read is used for the DFU in the UA device. +// The two read mechanisms are not compatible, so we must choose them at initialization. +#if !appconfUSB_ENABLED && appconfINTENT_ENABLED + rtos_qspi_flash_fast_read_init( + qspi_flash_ctx, + FLASH_CLKBLK, + PORT_SQI_CS, + PORT_SQI_SCLK, + PORT_SQI_SIO, + NULL, + qspi_fast_flash_read_transfer_nibble_swap, + 3, + QSPI_FLASH_CALIBRATION_ADDRESS); +#else fl_QuadDeviceSpec qspi_spec = BOARD_QSPI_SPEC; fl_QSPIPorts qspi_ports = { .qspiCS = PORT_SQI_CS, @@ -47,6 +66,7 @@ static void flash_init(void) PORT_SQI_SIO, NULL); #endif +#endif } static void gpio_init(void) @@ -90,15 +110,14 @@ static void i2c_init(void) { static rtos_driver_rpc_t i2c_rpc_config; -#if appconfI2C_CTRL_ENABLED -#if ON_TILE(I2C_CTRL_TILE_NO) +#if appconfI2C_DFU_ENABLED && ON_TILE(I2C_CTRL_TILE_NO) rtos_i2c_slave_init(i2c_slave_ctx, (1 << appconfI2C_IO_CORE), PORT_I2C_SCL, PORT_I2C_SDA, - appconf_CONTROL_I2C_DEVICE_ADDR); + appconfI2C_SLAVE_DEVICE_ADDR); #endif -#else + #if ON_TILE(I2C_TILE_NO) rtos_intertile_t *client_intertile_ctx[1] = {intertile_ctx}; rtos_i2c_master_init( @@ -119,7 +138,6 @@ static void i2c_init(void) &i2c_rpc_config, intertile_ctx); #endif -#endif } static void spi_init(void) @@ -136,6 +154,65 @@ static void spi_init(void) #endif } +#if ON_TILE(I2S_TILE_NO) && appconfRECOVER_MCLK_I2S_APP_PLL +static int *p_lock_status = NULL; +/// @brief Save the pointer to the pll lock_status variable +static void set_pll_lock_status_ptr(int* p) +{ + p_lock_status = p; +} +#endif + +static void platform_sw_pll_init(void) +{ +#if ON_TILE(I2S_TILE_NO) && appconfRECOVER_MCLK_I2S_APP_PLL + + port_t p_bclk = PORT_I2S_BCLK; + port_t p_mclk = PORT_MCLK; + port_t p_mclk_count = PORT_MCLK_COUNT; // Used internally by sw_pll + port_t p_bclk_count = PORT_BCLK_COUNT; // Used internally by sw_pll + xclock_t ck_bclk = I2S_CLKBLK; + + port_enable(p_mclk); + port_enable(p_bclk); + // NOTE: p_lrclk does not need to be enabled by the caller + + set_pll_lock_status_ptr(&sw_pll.lock_status); + // Create clock from mclk port and use it to clock the p_mclk_count port which will count MCLKs. + port_enable(p_mclk_count); + port_enable(p_bclk_count); + + // Allow p_mclk_count to count mclks + xclock_t clk_mclk = MCLK_CLKBLK; + clock_enable(clk_mclk); + clock_set_source_port(clk_mclk, p_mclk); + port_set_clock(p_mclk_count, clk_mclk); + clock_start(clk_mclk); + + // Allow p_bclk_count to count bclks + port_set_clock(p_bclk_count, ck_bclk); + sw_pll_lut_init(&sw_pll, + SW_PLL_15Q16(0.0), + SW_PLL_15Q16(1.0), + SW_PLL_15Q16(0.0), + PLL_CONTROL_LOOP_COUNT_INT, + PLL_RATIO, + (appconfBCLK_NOMINAL_HZ / appconfLRCLK_NOMINAL_HZ), + frac_values_90, + SW_PLL_NUM_LUT_ENTRIES(frac_values_90), + APP_PLL_CTL_REG, + APP_PLL_DIV_REG, + SW_PLL_NUM_LUT_ENTRIES(frac_values_90) / 2, + PLL_PPM_RANGE); + + debug_printf("Using SW PLL to track I2S input\n"); + sw_pll_ctx->sw_pll = &sw_pll; + sw_pll_ctx->p_mclk_count = p_mclk_count; + sw_pll_ctx->p_bclk_count = p_bclk_count; + +#endif +} + static void mics_init(void) { static rtos_driver_rpc_t mic_array_rpc_config; @@ -160,6 +237,7 @@ static void mics_init(void) static void i2s_init(void) { + #if appconfI2S_ENABLED #if appconfI2S_MODE == appconfI2S_MODE_MASTER static rtos_driver_rpc_t i2s_rpc_config; @@ -208,6 +286,8 @@ static void i2s_init(void) PORT_I2S_BCLK, PORT_I2S_LRCLK, I2S_CLKBLK); +#else + #error "Invalid I2S mode" #endif #else #if appconfI2S_MODE == appconfI2S_MODE_MASTER @@ -227,11 +307,43 @@ static void usb_init(void) #endif } +static void uart_init(void) +{ +#if appconfINTENT_ENABLED && ON_TILE(UART_TILE_NO) + hwtimer_t tmr_tx = hwtimer_alloc(); + + rtos_uart_tx_init( + uart_tx_ctx, + XS1_PORT_1A, /* J4:24*/ + appconfUART_BAUD_RATE, + 8, + UART_PARITY_NONE, + 1, + tmr_tx); +#endif +} + +void control_init() { +#if appconfI2C_DFU_ENABLED && ON_TILE(I2C_TILE_NO) + control_ret_t ret = CONTROL_SUCCESS; + ret = device_control_init(device_control_i2c_ctx, + DEVICE_CONTROL_HOST_MODE, + (NUM_TILE_0_SERVICERS + NUM_TILE_1_SERVICERS), + NULL, 0); + xassert(ret == CONTROL_SUCCESS); + + ret = device_control_start(device_control_i2c_ctx, + -1, + -1); + xassert(ret == CONTROL_SUCCESS); +#endif +} + void platform_init(chanend_t other_tile_c) { rtos_intertile_init(intertile_ctx, other_tile_c); rtos_intertile_init(intertile_usb_audio_ctx, other_tile_c); - + platform_sw_pll_init(); mclk_init(other_tile_c); gpio_init(); flash_init(); @@ -240,4 +352,6 @@ void platform_init(chanend_t other_tile_c) mics_init(); i2s_init(); usb_init(); + uart_init(); + control_init(); } diff --git a/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_start.c b/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_start.c index dcb10e463..73f05f60d 100644 --- a/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_start.c +++ b/examples/ffva/bsp_config/XK_VOICE_L71/platform/platform_start.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* System headers */ @@ -16,10 +16,8 @@ #include "dac3101.h" #include "usb_support.h" -#if appconfI2C_CTRL_ENABLED -#include "app_control/app_control.h" +#include "servicer.h" #include "device_control_i2c.h" -#endif extern void i2s_rate_conversion_enable(void); @@ -47,18 +45,15 @@ static void flash_start(void) static void i2c_master_start(void) { -#if !appconfI2C_CTRL_ENABLED rtos_i2c_master_rpc_config(i2c_master_ctx, appconfI2C_MASTER_RPC_PORT, appconfI2C_MASTER_RPC_PRIORITY); #if ON_TILE(I2C_TILE_NO) rtos_i2c_master_start(i2c_master_ctx); #endif -#endif } static void audio_codec_start(void) { -#if !appconfI2C_CTRL_ENABLED #if appconfI2S_ENABLED int ret = 0; #if ON_TILE(I2C_TILE_NO) @@ -71,18 +66,19 @@ static void audio_codec_start(void) rtos_intertile_rx_data(intertile_ctx, &ret, sizeof(ret)); #endif #endif -#endif } static void i2c_slave_start(void) { -#if appconfI2C_CTRL_ENABLED && ON_TILE(I2C_CTRL_TILE_NO) +#if appconfI2C_DFU_ENABLED && ON_TILE(I2C_CTRL_TILE_NO) rtos_i2c_slave_start(i2c_slave_ctx, device_control_i2c_ctx, (rtos_i2c_slave_start_cb_t) device_control_i2c_start_cb, (rtos_i2c_slave_rx_cb_t) device_control_i2c_rx_cb, (rtos_i2c_slave_tx_start_cb_t) device_control_i2c_tx_start_cb, (rtos_i2c_slave_tx_done_cb_t) NULL, + NULL, + NULL, appconfI2C_INTERRUPT_CORE, appconfI2C_TASK_PRIORITY); #endif @@ -141,6 +137,13 @@ static void usb_start(void) #endif } +static void uart_start(void) +{ +#if ON_TILE(UART_TILE_NO) + rtos_uart_tx_start(uart_tx_ctx); +#endif +} + void platform_start(void) { rtos_intertile_start(intertile_ctx); @@ -149,10 +152,12 @@ void platform_start(void) gpio_start(); flash_start(); i2c_master_start(); - i2c_slave_start(); audio_codec_start(); spi_start(); mics_start(); i2s_start(); usb_start(); + uart_start(); + // I2C slave can be started only after i2c_master_start() is completed + i2c_slave_start(); } diff --git a/examples/ffva/ffva.cmake b/examples/ffva/ffva.cmake index fb0fd4f6e..f7637dd73 100644 --- a/examples/ffva/ffva.cmake +++ b/examples/ffva/ffva.cmake @@ -1,11 +1,14 @@ #********************** # Gather Sources #********************** -file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c ) + +file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c) + set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src + ${CMAKE_CURRENT_LIST_DIR}/src/control + ${CMAKE_CURRENT_LIST_DIR}/src/dfu_int ${CMAKE_CURRENT_LIST_DIR}/src/usb - ${CMAKE_CURRENT_LIST_DIR}/src/ww_model_runner ) include(${CMAKE_CURRENT_LIST_DIR}/bsp_config/bsp_config.cmake) @@ -36,13 +39,15 @@ set(APP_COMPILE_DEFINITIONS set(APP_LINK_OPTIONS -lquadspi -report + -lotp3 ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope ) set(APP_COMMON_LINK_LIBRARIES - inferencing_tflite_micro rtos::freertos_usb + rtos::sw_services::device_control lib_src + lib_sw_pll ) #********************** @@ -81,10 +86,11 @@ endif() # XMOS Example Design Targets #********************** include(${CMAKE_CURRENT_LIST_DIR}/ffva_int.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/ffva_int_cyberon.cmake) include(${CMAKE_CURRENT_LIST_DIR}/ffva_ua.cmake) #********************** # Include FFVA Debug and Extension targets #********************** include(${CMAKE_CURRENT_LIST_DIR}/ffva_int_dev.cmake) -include(${CMAKE_CURRENT_LIST_DIR}/ffva_ua_dev.cmake) \ No newline at end of file +include(${CMAKE_CURRENT_LIST_DIR}/ffva_ua_dev.cmake) diff --git a/examples/ffva/ffva_int.cmake b/examples/ffva/ffva_int.cmake index 17af98380..3097fa1d4 100644 --- a/examples/ffva/ffva_int.cmake +++ b/examples/ffva/ffva_int.cmake @@ -7,10 +7,11 @@ set(FFVA_INT_COMPILE_DEFINITIONS appconfAEC_REF_DEFAULT=appconfAEC_REF_I2S appconfI2S_MODE=appconfI2S_MODE_SLAVE appconfI2S_AUDIO_SAMPLE_RATE=48000 - + appconfRECOVER_MCLK_I2S_APP_PLL=1 MIC_ARRAY_CONFIG_MCLK_FREQ=12288000 ) +query_tools_version() foreach(FFVA_AP ${FFVA_PIPELINES_INT}) #********************** # Tile Targets @@ -63,6 +64,8 @@ foreach(FFVA_AP ${FFVA_PIPELINES_INT}) #********************** create_run_target(example_ffva_int_${FFVA_AP}) create_debug_target(example_ffva_int_${FFVA_AP}) + message(variable="${XTC_VERSION_MAJOR}") + create_upgrade_img_target(example_ffva_int_${FFVA_AP} ${XTC_VERSION_MAJOR} ${XTC_VERSION_MINOR}) #********************** # Create data partition support targets diff --git a/examples/ffva/ffva_int_cyberon.cmake b/examples/ffva/ffva_int_cyberon.cmake new file mode 100644 index 000000000..6883f1649 --- /dev/null +++ b/examples/ffva/ffva_int_cyberon.cmake @@ -0,0 +1,191 @@ +#********************** +# ASR Language info +#********************** + +set(MODEL_LANGUAGE "english_usa") +set(CYBERON_COMMAND_NET_FILE "${CMAKE_CURRENT_LIST_DIR}/asr/model/english_usa/Hello_XMOS_pack_WithTxt.bin.Enc.NibbleSwap") + +#********************** +# QSPI Flash Layout +#********************** +set(BOOT_PARTITION_SIZE 0x100000) +set(FILESYSTEM_SIZE_KB 1024) +math(EXPR FILESYSTEM_SIZE_BYTES + "1024 * ${FILESYSTEM_SIZE_KB}" + OUTPUT_FORMAT HEXADECIMAL +) + +set(CALIBRATION_PATTERN_START_ADDRESS ${BOOT_PARTITION_SIZE}) + +math(EXPR FILESYSTEM_START_ADDRESS + "${CALIBRATION_PATTERN_START_ADDRESS} + ${LIB_QSPI_FAST_READ_DEFAULT_CAL_SIZE_BYTES}" + OUTPUT_FORMAT HEXADECIMAL +) + +math(EXPR MODEL_START_ADDRESS + "${FILESYSTEM_START_ADDRESS} + ${FILESYSTEM_SIZE_BYTES}" + OUTPUT_FORMAT HEXADECIMAL +) + +set(CALIBRATION_PATTERN_DATA_PARTITION_OFFSET 0) + +math(EXPR FILESYSTEM_DATA_PARTITION_OFFSET + "${CALIBRATION_PATTERN_DATA_PARTITION_OFFSET} + ${LIB_QSPI_FAST_READ_DEFAULT_CAL_SIZE_BYTES}" + OUTPUT_FORMAT DECIMAL +) + +math(EXPR MODEL_DATA_PARTITION_OFFSET + "${FILESYSTEM_DATA_PARTITION_OFFSET} + ${FILESYSTEM_SIZE_BYTES}" + OUTPUT_FORMAT DECIMAL +) + +set(FFVA_INT_CYBERON_COMPILE_DEFINITIONS + ${APP_COMPILE_DEFINITIONS} + appconfEXTERNAL_MCLK=1 + appconfI2S_ENABLED=1 + appconfUSB_ENABLED=0 + appconfINTENT_ENABLED=1 + appconfAEC_REF_DEFAULT=appconfAEC_REF_I2S + appconfI2S_MODE=appconfI2S_MODE_SLAVE + appconfI2S_AUDIO_SAMPLE_RATE=48000 + configENABLE_DEBUG_PRINTF=1 + appconfRECOVER_MCLK_I2S_APP_PLL=1 + QSPI_FLASH_FILESYSTEM_START_ADDRESS=${FILESYSTEM_START_ADDRESS} + QSPI_FLASH_MODEL_START_ADDRESS=${MODEL_START_ADDRESS} + QSPI_FLASH_CALIBRATION_ADDRESS=${CALIBRATION_PATTERN_START_ADDRESS} + ASR_CYBERON=1 + MIC_ARRAY_CONFIG_MCLK_FREQ=12288000 +) + +foreach(FFVA_AP ${FFVA_PIPELINES_INT}) + #********************** + # Tile Targets + #********************** + set(TARGET_NAME tile0_example_ffva_int_cyberon_${FFVA_AP}) + add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL) + target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES}) + target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES}) + target_compile_definitions(${TARGET_NAME} + PUBLIC + ${FFVA_INT_CYBERON_COMPILE_DEFINITIONS} + THIS_XCORE_TILE=0 + ) + target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) + target_link_libraries(${TARGET_NAME} + PUBLIC + ${APP_COMMON_LINK_LIBRARIES} + sln_voice::app::ffva::xk_voice_l71 + sln_voice::app::ffva::ap::${FFVA_AP} + sln_voice::app::asr::Cyberon + sln_voice::app::asr::device_memory + sln_voice::app::asr::gpio_ctrl + sln_voice::app::asr::intent_engine + sln_voice::app::asr::intent_handler + ) + target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) + unset(TARGET_NAME) + + set(TARGET_NAME tile1_example_ffva_int_cyberon_${FFVA_AP}) + add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL) + target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES}) + target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES}) + target_compile_definitions(${TARGET_NAME} + PUBLIC + ${FFVA_INT_CYBERON_COMPILE_DEFINITIONS} + THIS_XCORE_TILE=1 + ) + target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) + target_link_libraries(${TARGET_NAME} + PUBLIC + ${APP_COMMON_LINK_LIBRARIES} + sln_voice::app::ffva::xk_voice_l71 + sln_voice::app::ffva::ap::${FFVA_AP} + sln_voice::app::asr::Cyberon + sln_voice::app::asr::device_memory + sln_voice::app::asr::gpio_ctrl + sln_voice::app::asr::intent_engine + sln_voice::app::asr::intent_handler + ) + target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) + unset(TARGET_NAME) + + #********************** + # Merge binaries + #********************** + merge_binaries(example_ffva_int_cyberon_${FFVA_AP} tile0_example_ffva_int_cyberon_${FFVA_AP} tile1_example_ffva_int_cyberon_${FFVA_AP} 1) + + #********************** + # Create run and debug targets + #********************** + create_run_target(example_ffva_int_cyberon_${FFVA_AP}) + create_debug_target(example_ffva_int_cyberon_${FFVA_AP}) + + #********************** + # Create data partition support targets + #********************** + set(TARGET_NAME example_ffva_int_cyberon_${FFVA_AP}) + set(DATA_PARTITION_FILE ${TARGET_NAME}_data_partition.bin) + set(MODEL_FILE ${TARGET_NAME}_model.bin) + set(FATFS_FILE ${TARGET_NAME}_fat.fs) + set(FLASH_CAL_FILE ${LIB_QSPI_FAST_READ_ROOT_PATH}/lib_qspi_fast_read/calibration_pattern_nibble_swap.bin) + + add_custom_target(${MODEL_FILE} ALL + COMMAND ${CMAKE_COMMAND} -E copy ${CYBERON_COMMAND_NET_FILE} ${MODEL_FILE} + COMMENT + "Copy Cyberon NET file" + VERBATIM + ) + + create_filesystem_target( + #[[ Target ]] ${TARGET_NAME} + #[[ Input Directory ]] ${CMAKE_CURRENT_LIST_DIR}/filesystem_support/${MODEL_LANGUAGE} + #[[ Image Size ]] ${FILESYSTEM_SIZE_BYTES} + ) + + add_custom_command( + OUTPUT ${DATA_PARTITION_FILE} + COMMAND ${CMAKE_COMMAND} -E rm -f ${DATA_PARTITION_FILE} + COMMAND datapartition_mkimage -v -b 1 + -i ${FLASH_CAL_FILE}:${CALIBRATION_PATTERN_DATA_PARTITION_OFFSET} ${FATFS_FILE}:${FILESYSTEM_DATA_PARTITION_OFFSET} ${MODEL_FILE}:${MODEL_DATA_PARTITION_OFFSET} + -o ${DATA_PARTITION_FILE} + DEPENDS + ${MODEL_FILE} + make_fs_${TARGET_NAME} + ${FLASH_CAL_FILE} + COMMENT + "Create data partition" + VERBATIM + ) + + set(DATA_PARTITION_FILE_LIST + ${DATA_PARTITION_FILE} + ${MODEL_FILE} + ${FATFS_FILE} + ${FLASH_CAL_FILE} + ) + + set(DATA_PARTITION_DEPENDS_LIST + ${DATA_PARTITION_FILE} + ${MODEL_FILE} + make_fs_${TARGET_NAME} + ) + + # The list of files to copy and the dependency list for populating + # the data partition folder are identical. + create_data_partition_directory( + #[[ Target ]] ${TARGET_NAME} + #[[ Copy Files ]] "${DATA_PARTITION_FILE_LIST}" + #[[ Dependencies ]] "${DATA_PARTITION_DEPENDS_LIST}" + ) + + create_flash_app_target( + #[[ Target ]] ${TARGET_NAME} + #[[ Boot Partition Size ]] ${BOOT_PARTITION_SIZE} + #[[ Data Partition Contents ]] ${DATA_PARTITION_FILE} + #[[ Dependencies ]] ${DATA_PARTITION_FILE} + ) + + unset(DATA_PARTITION_FILE_LIST) + unset(DATA_PARTITION_DEPENDS_LIST) + +endforeach() diff --git a/examples/ffva/filesystem_support/english_usa/1.wav b/examples/ffva/filesystem_support/english_usa/1.wav new file mode 100644 index 000000000..ac6c951a1 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/1.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/10.wav b/examples/ffva/filesystem_support/english_usa/10.wav new file mode 100644 index 000000000..e98715cb4 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/10.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/11.wav b/examples/ffva/filesystem_support/english_usa/11.wav new file mode 100644 index 000000000..45a8c0c5b Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/11.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/12.wav b/examples/ffva/filesystem_support/english_usa/12.wav new file mode 100644 index 000000000..1482ef2d7 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/12.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/13.wav b/examples/ffva/filesystem_support/english_usa/13.wav new file mode 100644 index 000000000..e26c56215 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/13.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/14.wav b/examples/ffva/filesystem_support/english_usa/14.wav new file mode 100644 index 000000000..8b4628ffc Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/14.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/15.wav b/examples/ffva/filesystem_support/english_usa/15.wav new file mode 100644 index 000000000..28b9db748 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/15.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/16.wav b/examples/ffva/filesystem_support/english_usa/16.wav new file mode 100644 index 000000000..78c15e2ce Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/16.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/17.wav b/examples/ffva/filesystem_support/english_usa/17.wav new file mode 100644 index 000000000..c18b14507 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/17.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/18.wav b/examples/ffva/filesystem_support/english_usa/18.wav new file mode 100644 index 000000000..b45078f79 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/18.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/3.wav b/examples/ffva/filesystem_support/english_usa/3.wav new file mode 100644 index 000000000..9965a9139 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/3.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/4.wav b/examples/ffva/filesystem_support/english_usa/4.wav new file mode 100644 index 000000000..b00cbb937 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/4.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/5.wav b/examples/ffva/filesystem_support/english_usa/5.wav new file mode 100644 index 000000000..a6e18fbdf Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/5.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/50.wav b/examples/ffva/filesystem_support/english_usa/50.wav new file mode 100644 index 000000000..386c60b99 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/50.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/6.wav b/examples/ffva/filesystem_support/english_usa/6.wav new file mode 100644 index 000000000..5f56159e1 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/6.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/7.wav b/examples/ffva/filesystem_support/english_usa/7.wav new file mode 100644 index 000000000..e98f032a7 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/7.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/8.wav b/examples/ffva/filesystem_support/english_usa/8.wav new file mode 100644 index 000000000..a1a5c4256 Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/8.wav differ diff --git a/examples/ffva/filesystem_support/english_usa/9.wav b/examples/ffva/filesystem_support/english_usa/9.wav new file mode 100644 index 000000000..bb034482c Binary files /dev/null and b/examples/ffva/filesystem_support/english_usa/9.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/1.wav b/examples/ffva/filesystem_support/mandarin_mainland/1.wav new file mode 100644 index 000000000..ac6c951a1 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/1.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/10.wav b/examples/ffva/filesystem_support/mandarin_mainland/10.wav new file mode 100644 index 000000000..c93c4a6b8 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/10.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/11.wav b/examples/ffva/filesystem_support/mandarin_mainland/11.wav new file mode 100644 index 000000000..ceea109bb Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/11.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/12.wav b/examples/ffva/filesystem_support/mandarin_mainland/12.wav new file mode 100644 index 000000000..b44308a08 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/12.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/13.wav b/examples/ffva/filesystem_support/mandarin_mainland/13.wav new file mode 100644 index 000000000..8ffec9621 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/13.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/14.wav b/examples/ffva/filesystem_support/mandarin_mainland/14.wav new file mode 100644 index 000000000..36a395162 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/14.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/15.wav b/examples/ffva/filesystem_support/mandarin_mainland/15.wav new file mode 100644 index 000000000..3c9fd9a62 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/15.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/16.wav b/examples/ffva/filesystem_support/mandarin_mainland/16.wav new file mode 100644 index 000000000..f7389e14b Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/16.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/17.wav b/examples/ffva/filesystem_support/mandarin_mainland/17.wav new file mode 100644 index 000000000..df9612276 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/17.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/18.wav b/examples/ffva/filesystem_support/mandarin_mainland/18.wav new file mode 100644 index 000000000..6ff1832ea Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/18.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/3.wav b/examples/ffva/filesystem_support/mandarin_mainland/3.wav new file mode 100644 index 000000000..c75030414 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/3.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/4.wav b/examples/ffva/filesystem_support/mandarin_mainland/4.wav new file mode 100644 index 000000000..7784ea794 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/4.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/5.wav b/examples/ffva/filesystem_support/mandarin_mainland/5.wav new file mode 100644 index 000000000..7f859ea7b Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/5.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/50.wav b/examples/ffva/filesystem_support/mandarin_mainland/50.wav new file mode 100644 index 000000000..386c60b99 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/50.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/6.wav b/examples/ffva/filesystem_support/mandarin_mainland/6.wav new file mode 100644 index 000000000..652249057 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/6.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/7.wav b/examples/ffva/filesystem_support/mandarin_mainland/7.wav new file mode 100644 index 000000000..9cf623873 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/7.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/8.wav b/examples/ffva/filesystem_support/mandarin_mainland/8.wav new file mode 100644 index 000000000..d1879b378 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/8.wav differ diff --git a/examples/ffva/filesystem_support/mandarin_mainland/9.wav b/examples/ffva/filesystem_support/mandarin_mainland/9.wav new file mode 100644 index 000000000..28355dd55 Binary files /dev/null and b/examples/ffva/filesystem_support/mandarin_mainland/9.wav differ diff --git a/examples/ffva/src/FreeRTOSConfig.h b/examples/ffva/src/FreeRTOSConfig.h index 5bbec8d76..5d0afd459 100644 --- a/examples/ffva/src/FreeRTOSConfig.h +++ b/examples/ffva/src/FreeRTOSConfig.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef FREERTOS_CONFIG_H #define FREERTOS_CONFIG_H @@ -29,7 +29,7 @@ your application. */ #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 #define configUSE_TASK_NOTIFICATIONS 1 -#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 2 #define configUSE_MUTEXES 1 #define configUSE_RECURSIVE_MUTEXES 1 #define configUSE_COUNTING_SEMAPHORES 1 @@ -46,7 +46,7 @@ your application. */ #define configSUPPORT_STATIC_ALLOCATION 0 #define configSUPPORT_DYNAMIC_ALLOCATION 1 #if ON_TILE(0) -#define configTOTAL_HEAP_SIZE 128*1024 +#define configTOTAL_HEAP_SIZE 160*1024 #endif #if ON_TILE(1) #define configTOTAL_HEAP_SIZE 128*1024 diff --git a/examples/ffva/src/app_conf.h b/examples/ffva/src/app_conf.h index 4d9c860da..3d0993313 100644 --- a/examples/ffva/src/app_conf.h +++ b/examples/ffva/src/app_conf.h @@ -1,9 +1,24 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef APP_CONF_H_ #define APP_CONF_H_ +/** + * Application version numbers + * These values can be read by the xvf_dfu host app + * The xvf_dfu app is used with the FFVA-INT device only + */ +#ifndef APP_VERSION_MAJOR +#define APP_VERSION_MAJOR 255 +#endif +#ifndef APP_VERSION_MINOR +#define APP_VERSION_MINOR 254 +#endif +#ifndef APP_VERSION_PATCH +#define APP_VERSION_PATCH 253 +#endif + /* Intertile port settings */ #define appconfUSB_AUDIO_PORT 0 #define appconfGPIO_T0_RPC_PORT 1 @@ -15,10 +30,15 @@ #define appconfAUDIOPIPELINE_PORT 7 #define appconfI2S_OUTPUT_SLAVE_PORT 8 +#ifndef appconfINTENT_ENGINE_READY_SYNC_PORT +#define appconfINTENT_ENGINE_READY_SYNC_PORT 18 +#endif /* appconfINTENT_ENGINE_READY_SYNC_PORT */ + /* Application tile specifiers */ #include "platform/driver_instances.h" -#define FS_TILE_NO FLASH_TILE_NO -#define AUDIO_PIPELINE_TILE_NO MICARRAY_TILE_NO +#define ASR_TILE_NO FLASH_TILE_NO +#define FS_TILE_NO FLASH_TILE_NO +#define AUDIO_PIPELINE_OUTPUT_TILE_NO FLASH_TILE_NO /* Audio Pipeline Configuration */ #define appconfAUDIO_CLOCK_FREQUENCY MIC_ARRAY_CONFIG_MCLK_FREQ @@ -28,6 +48,65 @@ /* If in channel sample format, appconfAUDIO_PIPELINE_FRAME_ADVANCE == MIC_ARRAY_CONFIG_SAMPLES_PER_FRAME*/ #define appconfAUDIO_PIPELINE_FRAME_ADVANCE MIC_ARRAY_CONFIG_SAMPLES_PER_FRAME +/* Enable audio response output */ +#ifndef appconfAUDIO_PLAYBACK_ENABLED +#define appconfAUDIO_PLAYBACK_ENABLED 1 +#endif + +/* Intent Engine Configuration */ +#define appconfINTENT_FRAME_BUFFER_MULT (8*2) /* total buffer size is this value * MIC_ARRAY_CONFIG_SAMPLES_PER_FRAME */ +#define appconfINTENT_SAMPLE_BLOCK_LENGTH 240 + +/* Maximum delay between a wake up phrase and command phrase */ +#ifndef appconfINTENT_RESET_DELAY_MS +#if appconfAUDIO_PLAYBACK_ENABLED +#define appconfINTENT_RESET_DELAY_MS 5000 +#else +#define appconfINTENT_RESET_DELAY_MS 4000 +#endif +#endif + +/* Output raw inferences, if set to 0, a state machine requires a wake up phrase + * before a command phrase */ +#ifndef appconfINTENT_RAW_OUTPUT +#define appconfINTENT_RAW_OUTPUT 0 +#endif + +/* Maximum number of detected intents to hold */ +#ifndef appconfINTENT_QUEUE_LEN +#define appconfINTENT_QUEUE_LEN 10 +#endif + +/* External wakeup pin edge on intent found. 0 for rising edge, 1 for falling edge */ +#ifndef appconfINTENT_WAKEUP_EDGE_TYPE +#define appconfINTENT_WAKEUP_EDGE_TYPE 0 +#endif + +/* Delay between external wakeup pin edge and intent output */ +#ifndef appconfINTENT_TRANSPORT_DELAY_MS +#define appconfINTENT_TRANSPORT_DELAY_MS 50 +#endif + +#ifndef appconfINTENT_I2C_MASTER_OUTPUT_ENABLED +#define appconfINTENT_I2C_MASTER_OUTPUT_ENABLED 1 +#endif + +#ifndef appconfINTENT_I2C_MASTER_DEVICE_ADDR +#define appconfINTENT_I2C_MASTER_DEVICE_ADDR 0x01 +#endif + +#ifndef appconfINTENT_UART_OUTPUT_ENABLED +#define appconfINTENT_UART_OUTPUT_ENABLED 1 +#endif + +#ifndef appconfINTENT_UART_DEBUG_INFO_ENABLED +#define appconfINTENT_UART_DEBUG_INFO_ENABLED 0 +#endif + +#ifndef appconfUART_BAUD_RATE +#define appconfUART_BAUD_RATE 9600 +#endif + /** * A positive delay will delay mics * A negative delay will delay ref @@ -70,10 +149,6 @@ #define appconfUSB_ENABLED 0 #endif -#ifndef appconfWW_ENABLED -#define appconfWW_ENABLED 1 -#endif - #ifndef appconfUSB_AUDIO_SAMPLE_RATE #define appconfUSB_AUDIO_SAMPLE_RATE appconfAUDIO_PIPELINE_SAMPLE_RATE #endif @@ -99,8 +174,14 @@ #define appconfI2S_TDM_ENABLED 0 #endif +#ifndef appconfI2S_MODE_MASTER #define appconfI2S_MODE_MASTER 0 +#endif + +#ifndef appconfI2S_MODE_SLAVE #define appconfI2S_MODE_SLAVE 1 +#endif + #ifndef appconfI2S_MODE #define appconfI2S_MODE appconfI2S_MODE_MASTER #endif @@ -132,9 +213,6 @@ #include "app_conf_check.h" -/* WW Config */ -#define appconfWW_FRAMES_PER_INFERENCE (160) - /* I/O and interrupt cores for Tile 0 */ /* Note, USB and SPI are mutually exclusive */ #define appconfXUD_IO_CORE 1 /* Must be kept off core 0 with the RTOS tick ISR */ @@ -161,6 +239,20 @@ #define appconfUSB_AUDIO_TASK_PRIORITY (configMAX_PRIORITIES/2 + 1) #define appconfSPI_TASK_PRIORITY (configMAX_PRIORITIES/2 + 1) #define appconfQSPI_FLASH_TASK_PRIORITY (configMAX_PRIORITIES/2 + 0) -#define appconfWW_TASK_PRIORITY (configMAX_PRIORITIES/2 - 1) +#define appconfINTENT_MODEL_RUNNER_TASK_PRIORITY (configMAX_PRIORITIES - 2) +#define appconfLED_TASK_PRIORITY (configMAX_PRIORITIES / 2 - 1) + +#if appconfI2S_MODE==appconfI2S_MODE_SLAVE +/* Software PLL settings for mclk recovery configurations */ +/* see fractions.h and register_setup.h for other pll settings */ +#define appconfLRCLK_NOMINAL_HZ appconfI2S_AUDIO_SAMPLE_RATE +#define appconfBCLK_NOMINAL_HZ (appconfLRCLK_NOMINAL_HZ * 64) +#define PLL_RATIO (MIC_ARRAY_CONFIG_MCLK_FREQ / appconfLRCLK_NOMINAL_HZ) +#define PLL_CONTROL_LOOP_COUNT_INT 512 // How many refclk ticks (LRCLK) per control loop iteration. Aim for ~100Hz +#define PLL_PPM_RANGE 1000 // Max allowable diff in clk count. For the PID constants we + // have chosen, this number should be larger than the number + // of elements in the look up table as the clk count diff is + // added to the LUT index with a multiplier of 1. Only used for INT mclkless +#endif #endif /* APP_CONF_H_ */ diff --git a/examples/ffva/src/app_conf_check.h b/examples/ffva/src/app_conf_check.h index 9ca85d768..753eab69a 100644 --- a/examples/ffva/src/app_conf_check.h +++ b/examples/ffva/src/app_conf_check.h @@ -1,4 +1,4 @@ -// Copyright 2021-2023 XMOS LIMITED. +// Copyright 2021-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef APP_CONF_CHECK_H_ @@ -12,13 +12,17 @@ #error Cannot use USB with an external mclk source #endif +#if appconfUSB_ENABLED && appconfINTENT_ENABLED +#error Cannot use wakeword engine in USB configurations +#endif + #if appconfI2S_TDM_ENABLED && appconfI2S_AUDIO_SAMPLE_RATE != 3*appconfAUDIO_PIPELINE_SAMPLE_RATE #error appconfI2S_AUDIO_SAMPLE_RATE must be 48000 to use I2S TDM #endif #if XK_VOICE_L71 #if appconfSPI_OUTPUT_ENABLED -#error SPI audio output not currently supported on XVF3610 board +#error SPI audio output not currently supported on XK-VOICE-L71 board #endif #endif diff --git a/examples/ffva/src/control/cmd_map.h b/examples/ffva/src/control/cmd_map.h new file mode 100644 index 000000000..71467e201 --- /dev/null +++ b/examples/ffva/src/control/cmd_map.h @@ -0,0 +1,39 @@ +// Copyright 2022-2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#pragma once + +#include +#include "device_control_shared.h" + +// Types of commands in the Command ID enum space - +// - Dedicated: Commands dedicated only for the resource +// - For SHF this is further spilt into dedicated SHF commands and dedicated custom commands +// - Shared: Commands shared between a resource and its servicer. These are present in the servicer's command map only though respources process them as well. (Used for special commands protocol) +// - External: space reserved for customers to add commands. +#define DEDICATED_COMMANDS_START_OFFSET (0) +#define SHARED_COMMANDS_START_OFFSET (90) +#define EXTERNAL_COMMANDS_START_OFFSET (110) +// Servicers will have commands in the above 4 categories. +// Resources will have commands in the dedicated, reserved and broadcast categories. + + +typedef enum +{ + CMD_READ_ONLY, + CMD_READ_WRITE, + CMD_WRITE_ONLY +}cmd_rw_type_t; + +typedef struct +{ + uint8_t cmd_id; + uint8_t num_vals; + uint8_t bytes_per_val; + uint8_t cmd_rw_type; +}control_cmd_info_t; + +typedef struct { + int32_t num_commands; + control_cmd_info_t *commands; +}command_map_t; diff --git a/examples/ffva/src/control/servicer.c b/examples/ffva/src/control/servicer.c new file mode 100644 index 000000000..9a93d1153 --- /dev/null +++ b/examples/ffva/src/control/servicer.c @@ -0,0 +1,168 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#define DEBUG_UNIT SERVICER_TASK +#ifndef DEBUG_PRINT_ENABLE_SERVICER_TASK + #define DEBUG_PRINT_ENABLE_SERVICER_TASK 0 +#endif +#include "debug_print.h" +#include +#include +#include "platform/platform_conf.h" +#include "device_control_i2c.h" +#include "servicer.h" +#include "dfu_servicer.h" + +#if appconfI2C_DFU_ENABLED && ON_TILE(I2C_CTRL_TILE_NO) +static device_control_t device_control_i2c_ctx_s; +device_control_t *device_control_i2c_ctx = (device_control_t *) &device_control_i2c_ctx_s; +device_control_t *device_control_ctxs[APP_CONTROL_TRANSPORT_COUNT] = { + (device_control_t *) &device_control_i2c_ctx_s, +}; +#endif + +//-----------------Servicer read write callback functions-----------------------// +DEVICE_CONTROL_CALLBACK_ATTR +control_ret_t read_cmd(control_resid_t resid, control_cmd_t cmd, uint8_t *payload, size_t payload_len, void *app_data) +{ + control_ret_t ret = CONTROL_SUCCESS; + servicer_t *servicer = (servicer_t*)app_data; + + // For read commands, payload[0] is reserved from status. So payload_len is one more than the payload_len stored in the resource command map + payload_len -= 1; + uint8_t *payload_ptr = &payload[1]; //Excluding the status byte, which is updated later. + + debug_printf("Servicer ID %d on tile %d received READ command %02x for resid %02x\n\t",servicer->id, THIS_XCORE_TILE, cmd, resid); + debug_printf("The command is requesting %d bytes\n\t", payload_len); + + + control_resource_info_t *current_res_info = get_res_info(resid, servicer); + xassert(current_res_info != NULL); // This should never happen + control_cmd_info_t *current_cmd_info; + ret = validate_cmd(¤t_cmd_info, current_res_info, cmd, payload_ptr, payload_len); + if(ret != CONTROL_SUCCESS) + { + payload[0] = ret; // Update status in byte 0 + return ret; + } + // Check if command is for the servicer itself + if(current_res_info->resource == servicer->res_info[0].resource) + { + ret = servicer_read_cmd(current_res_info, cmd, payload_ptr, payload_len); + payload[0] = ret; + return ret; + } + return CONTROL_ERROR; +} + +DEVICE_CONTROL_CALLBACK_ATTR +control_ret_t write_cmd(control_resid_t resid, control_cmd_t cmd, const uint8_t *payload, size_t payload_len, void *app_data) +{ + control_ret_t ret = CONTROL_SUCCESS; + servicer_t *servicer = (servicer_t*)app_data; + //debug_printf("Device control WRITE. Servicer ID %d\n\t", servicer->id); + + debug_printf("Servicer ID %d on tile %d received WRITE command %02x for resid %02x\n\t", servicer->id, THIS_XCORE_TILE, cmd, resid); + debug_printf("The command has %d bytes\n\t", payload_len); + + control_resource_info_t *current_res_info = get_res_info(resid, servicer); + xassert(current_res_info != NULL); + control_cmd_info_t *current_cmd_info; + ret = validate_cmd(¤t_cmd_info, current_res_info, cmd, payload, payload_len); + if(ret != CONTROL_SUCCESS) + { + return ret; + } + // Check if command is for the servicer itself + if(current_res_info->resource == servicer->res_info[0].resource) + { + ret = servicer_write_cmd(current_res_info, cmd, payload, payload_len); + return ret; + } + return CONTROL_ERROR; +} + +// Initialise packet payload pointers to point to valid memory. + + +//-----------------Servicer helper functions-----------------------// +// Return a pointer to the control_cmd_info_t structure for a given command ID. Return NULL if command not found in the +// command map for the resource. +control_cmd_info_t* get_cmd_info(uint8_t cmd_id, const control_resource_info_t *res_info) +{ + for(int i=0; icommand_map.num_commands; i++) + { + if(res_info->command_map.commands[i].cmd_id == cmd_id) + { + return &res_info->command_map.commands[i]; + } + } + return NULL; +} + +// Return a pointer to the servicer's control_resource_info_t structure for a given resource ID. +// Return NULL if the resource ID is not found in the list of resources serviced by the servicer. +control_resource_info_t* get_res_info(control_resid_t resource, const servicer_t *servicer) +{ + for(int res=0; resnum_resources; res++) + { + // Get the cmd_info for the current command + if(servicer->res_info[res].resource == resource) + { + return &servicer->res_info[res]; + } + } + return NULL; +} + +// Validate the command from the host against that commands information in the stored command_map +control_ret_t validate_cmd(control_cmd_info_t **cmd_info, + control_resource_info_t *res_info, + control_cmd_t cmd, + const uint8_t *payload, + size_t payload_len) +{ + control_ret_t ret = CONTROL_SUCCESS; + *cmd_info = get_cmd_info(CONTROL_CMD_CLEAR_READ(cmd), res_info); + if(*cmd_info == NULL) + { + return SERVICER_WRONG_COMMAND_ID; + } + + // Validate non special command length + // Don't do payload check for special commands since for the last filter chunk, host might request less than the payload length specified in the cmd_map + + if(payload_len != (*cmd_info)->bytes_per_val * (*cmd_info)->num_vals) + { + return SERVICER_WRONG_COMMAND_LEN; + } + // Payload validation happens either on the host or in the specific command handlers. No generic payload validation is done in the servicer. + + return ret; +} + +// Process write commands directed to the servicer resource +control_ret_t servicer_write_cmd(control_resource_info_t *res_info, control_cmd_t cmd, const uint8_t *payload, size_t payload_len) +{ + // Handle write commands directed to a servicer resource + switch(res_info->resource) + { + case DFU_CONTROLLER_SERVICER_RESID: + return dfu_servicer_write_cmd(res_info, cmd, payload, payload_len); + break; + } + return CONTROL_SUCCESS; +} + +// Process read commands directed to the servicer resource +control_ret_t servicer_read_cmd(control_resource_info_t *res_info, control_cmd_t cmd, uint8_t *payload, size_t payload_len) +{ + control_ret_t ret = CONTROL_SUCCESS; + // Handle read commands directed to a servicer resource + switch(res_info->resource) + { + case DFU_CONTROLLER_SERVICER_RESID: + ret = dfu_servicer_read_cmd(res_info, cmd, payload, payload_len); + break; + } + return ret; +} diff --git a/examples/ffva/src/control/servicer.h b/examples/ffva/src/control/servicer.h new file mode 100644 index 000000000..11ebd21cc --- /dev/null +++ b/examples/ffva/src/control/servicer.h @@ -0,0 +1,124 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#pragma once +#include "device_control.h" +#include "cmd_map.h" + +#define NUM_TILE_0_SERVICERS (1) // only DFU servicer is used +#define NUM_TILE_1_SERVICERS (0) // no control servicer + +extern device_control_t *device_control_i2c_ctx; +extern device_control_t *device_control_ctxs[1]; + +/** + * Clears the read bit on a command code + * + * \param[in,out] c The command code to clear the read bit on. + */ +#define CONTROL_CMD_CLEAR_READ(c) ((c) & ~0x80) + +// Structure encapsulating all the information about a resource +typedef struct +{ + control_resid_t resource; + command_map_t command_map; +}control_resource_info_t; + +typedef struct { + uint32_t start_io; // set to 1 on one servicer per tile to make it responsible for starting the IO tasks on that tile. + int32_t id; // Unique ID for the servicer. Used for debugging. + // Num resources + int32_t num_resources; + // Resource ID and command map for every resource + control_resource_info_t *res_info; +}servicer_t; + +// Servicer device_control callback functions +/** + * @brief Device control callback function to handle a read command. + * + * @param resid Resource ID of the command + * @param cmd Command ID of the command + * @param payload Pointer to the payload buffer that needs to be updated with the read command response. + * @param payload_len Length of the payload buffer + * @param app_data Application specific data. + * @return CONTROL_SUCCESS is command is handled successfully, + * otherwise control_ret_t error status indicating the error. + */ +extern DEVICE_CONTROL_CALLBACK_ATTR +control_ret_t read_cmd(control_resid_t resid, control_cmd_t cmd, uint8_t *payload, size_t payload_len, void *app_data); + +/** + * @brief Device control callback function to handle a write command + * + * @param resid Resource ID of the command + * @param cmd Command ID of the command + * @param payload Pointer to the payload buffer containing the payload the host wants to write to the device. + * @param payload_len Length of the payload buffer + * @param app_data Application specific data + * @return CONTROL_SUCCESS is command is handled successfully, + * otherwise control_ret_t error status indicating the error. + */ +extern DEVICE_CONTROL_CALLBACK_ATTR +control_ret_t write_cmd(control_resid_t resid, control_cmd_t cmd, const uint8_t *payload, size_t payload_len, void *app_data); + +// Servicer helper functions +/** + * @brief Check if a command exists in the command map for a given resource and return the pointer to the cmd info object for the given command + * + * @param cmd_id Command ID for which the control_cmd_info_t object is required. + * @param res_info Pointer to the resource info which contains all the command info objects for a given resource. + * @return Pointer to a control_cmd_info_t object when one is found for the given Command ID, NULL otherwise. + */ +control_cmd_info_t* get_cmd_info(uint8_t cmd_id, const control_resource_info_t *res_info); + +/** + * @brief Check if a resource ID is one of the resources supported by a servicer and return a pointer to the resource info object. + * + * @param resource Resource ID that needs to be checked. + * @param servicer Pointer to the servicer state structure that holds all the resource info objects for the servicer. + * @return Pointer to the resource_info_t object when one is found for a given resource ID, NULL otherwise. + */ +control_resource_info_t* get_res_info(control_resid_t resource, const servicer_t *servicer); + +/** + * @brief Validate the command received in the servicer and return a pointer to the command info if the command is valid. + * + * All checks related to the command such as command ID being valid, correctness of the payload length, + * validation of the actual payload for write commands are done in this function. + * + * @param cmd_info Pointer in which the address of the command info is returned if this is a valid command/ + * @param res_info Resource info of the resource the command is meant for. + * @param cmd Command ID of the command that needs validating + * @param payload Payload buffer of the command that needs validating. + * @param payload_len Payload length of the payload. + * @return CONTROL_SUCCESS if the command is found to be valid for the given resource. control_ret_t error otherwise + * indicating the error code of the specific validation check that failed. + */ +control_ret_t validate_cmd(control_cmd_info_t **cmd_info, + control_resource_info_t *res_info, + control_cmd_t cmd, + const uint8_t *payload, + size_t payload_len); + +/** + * @brief Function for handling write commands directed to the servicer resource itself. + * + * @param resid Command Resource ID + * @param cmd Command Command ID + * @param payload Command write payload buffer + * @param payload_len Length of the payload buffer + * @return CONTROL_SUCCESS if write command processed successfully. contro_ret_t error status otherwise. + */ +control_ret_t servicer_write_cmd(control_resource_info_t *res_info, control_cmd_t cmd, const uint8_t *payload, size_t payload_len); + +/** + * @brief Function for handling read commands directed to the servicer resource itself. + * + * @param resid Command Resource ID + * @param cmd Command Command ID + * @param payload Payload buffer to populate with the read response + * @param payload_len Length of the payload buffer + * @return CONTROL_SUCCESS if read command processed successfully. contro_ret_t error status otherwise. + */ +control_ret_t servicer_read_cmd(control_resource_info_t *res_info, control_cmd_t cmd, uint8_t *payload, size_t payload_len); diff --git a/examples/ffva/src/dfu_int/dfu_cmds.h b/examples/ffva/src/dfu_int/dfu_cmds.h new file mode 100644 index 000000000..186f35c0c --- /dev/null +++ b/examples/ffva/src/dfu_int/dfu_cmds.h @@ -0,0 +1,97 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#pragma once + +#include + +// Note: The enums are wrapped around a #ifndef block to support autogenerating cmd_map files from the +// BeClearSuperHandsFree.h defines. The defines in BeClearSuperHandsFree.h are visible in the device +// but not in the host, so the #ifndef is needed to keep the cmd_map files common between device and host. + +// DFU_CONTROLLER_SERVICER_RESID commands +enum e_dfu_controller_servicer_resid_cmds +{ +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_DETACH + DFU_CONTROLLER_SERVICER_RESID_DFU_DETACH = 0, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_DNLOAD + DFU_CONTROLLER_SERVICER_RESID_DFU_DNLOAD = 1, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_UPLOAD + DFU_CONTROLLER_SERVICER_RESID_DFU_UPLOAD = 2, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATUS + DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATUS = 3, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_CLRSTATUS + DFU_CONTROLLER_SERVICER_RESID_DFU_CLRSTATUS = 4, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATE + DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATE = 5, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_ABORT + DFU_CONTROLLER_SERVICER_RESID_DFU_ABORT = 6, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_SETALTERNATE + DFU_CONTROLLER_SERVICER_RESID_DFU_SETALTERNATE = 64, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK + DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK = 65, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_GETVERSION + DFU_CONTROLLER_SERVICER_RESID_DFU_GETVERSION = 88, +#endif +#ifndef DFU_CONTROLLER_SERVICER_RESID_DFU_REBOOT + DFU_CONTROLLER_SERVICER_RESID_DFU_REBOOT = 89, +#endif + NUM_DFU_CONTROLLER_SERVICER_RESID_CMDS = 11 +}; + +// DFU_CONTROLLER_SERVICER_RESID number of elements +// number of values of type dfu_controller_servicer_resid_dfu_detach_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_DETACH +#define DFU_CONTROLLER_SERVICER_RESID_DFU_DETACH_NUM_VALUES (1) +// number of values of type dfu_controller_servicer_resid_dfu_dnload_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_DNLOAD +#define DFU_CONTROLLER_SERVICER_RESID_DFU_DNLOAD_NUM_VALUES (130) +// number of values of type dfu_controller_servicer_resid_dfu_upload_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_UPLOAD +#define DFU_CONTROLLER_SERVICER_RESID_DFU_UPLOAD_NUM_VALUES (130) +// number of values of type dfu_controller_servicer_resid_dfu_getstatus_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATUS +#define DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATUS_NUM_VALUES (5) +// number of values of type dfu_controller_servicer_resid_dfu_clrstatus_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_CLRSTATUS +#define DFU_CONTROLLER_SERVICER_RESID_DFU_CLRSTATUS_NUM_VALUES (1) +// number of values of type dfu_controller_servicer_resid_dfu_getstate_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATE +#define DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATE_NUM_VALUES (1) +// number of values of type dfu_controller_servicer_resid_dfu_abort_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_ABORT +#define DFU_CONTROLLER_SERVICER_RESID_DFU_ABORT_NUM_VALUES (1) +// number of values of type dfu_controller_servicer_resid_dfu_setalternate_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_SETALTERNATE +#define DFU_CONTROLLER_SERVICER_RESID_DFU_SETALTERNATE_NUM_VALUES (1) +// number of values of type dfu_controller_servicer_resid_dfu_transferblock_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK +#define DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK_NUM_VALUES (2) +// number of values of type dfu_controller_servicer_resid_dfu_getversion_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_GETVERSION +#define DFU_CONTROLLER_SERVICER_RESID_DFU_GETVERSION_NUM_VALUES (3) +// number of values of type dfu_controller_servicer_resid_dfu_reboot_t expected by DFU_CONTROLLER_SERVICER_RESID_DFU_REBOOT +#define DFU_CONTROLLER_SERVICER_RESID_DFU_REBOOT_NUM_VALUES (1) + +// DFU_CONTROLLER_SERVICER_RESID types +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_DETACH +typedef uint8_t dfu_controller_servicer_resid_dfu_detach_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_DNLOAD +typedef uint8_t dfu_controller_servicer_resid_dfu_dnload_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_UPLOAD +typedef uint8_t dfu_controller_servicer_resid_dfu_upload_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATUS +typedef uint8_t dfu_controller_servicer_resid_dfu_getstatus_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_CLRSTATUS +typedef uint8_t dfu_controller_servicer_resid_dfu_clrstatus_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATE +typedef uint8_t dfu_controller_servicer_resid_dfu_getstate_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_ABORT +typedef uint8_t dfu_controller_servicer_resid_dfu_abort_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_SETALTERNATE +typedef uint8_t dfu_controller_servicer_resid_dfu_setalternate_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK +typedef uint8_t dfu_controller_servicer_resid_dfu_transferblock_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_GETVERSION +typedef uint8_t dfu_controller_servicer_resid_dfu_getversion_t; +// type expected by DFU_CONTROLLER_SERVICER_RESID_DFU_REBOOT +typedef uint8_t dfu_controller_servicer_resid_dfu_reboot_t; diff --git a/examples/ffva/src/dfu_int/dfu_cmds_map.h b/examples/ffva/src/dfu_int/dfu_cmds_map.h new file mode 100644 index 000000000..be59a2e71 --- /dev/null +++ b/examples/ffva/src/dfu_int/dfu_cmds_map.h @@ -0,0 +1,24 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" + +// DFU_CONTROLLER_SERVICER_RESID command map +// This array may be unused as servicers can be moved between tiles +// Unused variable warnings are suppressed in this header file +static control_cmd_info_t dfu_controller_servicer_resid_cmd_map[] = +{ + { DFU_CONTROLLER_SERVICER_RESID_DFU_DETACH, 1, sizeof(uint8_t), CMD_WRITE_ONLY }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_DNLOAD, 130, sizeof(uint8_t), CMD_WRITE_ONLY }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_UPLOAD, 130, sizeof(uint8_t), CMD_READ_ONLY }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATUS, 5, sizeof(uint8_t), CMD_READ_ONLY }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_CLRSTATUS, 1, sizeof(uint8_t), CMD_WRITE_ONLY }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATE, 1, sizeof(uint8_t), CMD_READ_ONLY }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_ABORT, 1, sizeof(uint8_t), CMD_WRITE_ONLY }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_SETALTERNATE, 1, sizeof(uint8_t), CMD_WRITE_ONLY }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK, 2, sizeof(uint8_t), CMD_READ_WRITE }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_GETVERSION, 3, sizeof(uint8_t), CMD_READ_ONLY }, + { DFU_CONTROLLER_SERVICER_RESID_DFU_REBOOT, 1, sizeof(uint8_t), CMD_WRITE_ONLY }, +}; +#pragma clang diagnostic pop diff --git a/examples/ffva/src/dfu_int/dfu_common.c b/examples/ffva/src/dfu_int/dfu_common.c new file mode 100644 index 000000000..3801aafb0 --- /dev/null +++ b/examples/ffva/src/dfu_int/dfu_common.c @@ -0,0 +1,166 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#define DEBUG_UNIT DFU_COMMON +#ifndef DEBUG_PRINT_ENABLE_DFU_COMMON +#define DEBUG_PRINT_ENABLE_DFU_COMMON 0 +#endif +#include "debug_print.h" + +#include +#include +#include "quadflashlib.h" + +#include "dfu_common.h" +#include "rtos_dfu_image.h" +#include "rtos_qspi_flash.h" +#include "platform/driver_instances.h" +#include "platform/platform_conf.h" // needed for appconfI2C_DFU_ENABLED + +static size_t bytes_avail = 0; +static uint32_t dn_base_addr = 0; +static size_t total_len = 0; + +uint32_t dfu_common_write_to_flash(uint8_t alt, + uint16_t block_num, + uint8_t const *data, + uint16_t length) +{ + rtos_printf("Received Alt %d BlockNum %d of length %d\n", alt, block_num, length); + uint32_t return_value = 0; // DFU_STATUS_OK + + unsigned data_partition_base_addr = rtos_dfu_image_get_data_partition_addr(dfu_image_ctx); + switch(alt) { + default: + case 0: + return_value = 3; //DFU_STATUS_ERR_WRITE + break; + case 1: + if (dn_base_addr == 0) { + total_len = 0; + dn_base_addr = rtos_dfu_image_get_upgrade_addr(dfu_image_ctx); + bytes_avail = data_partition_base_addr - dn_base_addr; + } + /* fallthrough */ + case 2: + if (dn_base_addr == 0) { + total_len = 0; + dn_base_addr = data_partition_base_addr; + bytes_avail = rtos_qspi_flash_size_get(qspi_flash_ctx) - dn_base_addr; + } + rtos_printf("Using addr 0x%x\nsize %u\n", dn_base_addr, bytes_avail); + if(length > 0) { + unsigned cur_addr = dn_base_addr + (block_num * length); + if((bytes_avail - total_len) >= length) { + rtos_printf("write %d at 0x%x\n", length, cur_addr); + + size_t sector_size = rtos_qspi_flash_sector_size_get(qspi_flash_ctx); + xassert(length == sector_size); + + uint8_t *tmp_buf = rtos_osal_malloc( sizeof(uint8_t) * sector_size); + rtos_qspi_flash_lock(qspi_flash_ctx); + { + rtos_qspi_flash_read( + qspi_flash_ctx, + tmp_buf, + cur_addr, + sector_size); + memcpy(tmp_buf, data, length); + rtos_qspi_flash_erase( + qspi_flash_ctx, + cur_addr, + sector_size); + rtos_qspi_flash_write( + qspi_flash_ctx, + (uint8_t *) tmp_buf, + cur_addr, + sector_size); + } + rtos_qspi_flash_unlock(qspi_flash_ctx); + rtos_osal_free(tmp_buf); + total_len += length; + } else { + rtos_printf("Insufficient space\n"); + return_value = 8; //DFU_STATUS_ERR_ADDRESS; + } + } + + break; + } + + return return_value; +} + +uint32_t dfu_common_make_manifest() +{ + debug_printf("Download completed, enter manifestation\n"); + + /* Perform a read to ensure all writes have been flushed */ + uint32_t dummy = 0; + rtos_qspi_flash_read( + qspi_flash_ctx, + (uint8_t *)&dummy, + 0, + sizeof(dummy)); + + /* Reset download */ + dn_base_addr = 0; + + // flashing op for manifest is complete without error + // Application can perform checksum. + // Should it fail, return appropriate status such as errVERIFY. + return 0; // DFU_STATUS_OK +} + +uint16_t dfu_common_read_from_flash(uint8_t alt, + uint16_t block_num, + uint8_t *data, + uint16_t length) +{ + uint32_t endaddr = 0; + uint16_t retval = 0; + uint32_t addr = block_num * length; + + rtos_printf("Upload Alt %d BlockNum %d of length %d\n", alt, block_num, length); + + switch(alt) { + default: + break; + case 0: + if (rtos_dfu_image_get_factory_size(dfu_image_ctx) > 0) { + addr += rtos_dfu_image_get_factory_addr(dfu_image_ctx); + endaddr = rtos_dfu_image_get_factory_addr(dfu_image_ctx) + rtos_dfu_image_get_factory_size(dfu_image_ctx); + } + break; + case 1: + if (rtos_dfu_image_get_upgrade_size(dfu_image_ctx) > 0) { + addr += rtos_dfu_image_get_upgrade_addr(dfu_image_ctx); + endaddr = rtos_dfu_image_get_upgrade_addr(dfu_image_ctx) + rtos_dfu_image_get_upgrade_size(dfu_image_ctx); + } + break; + case 2: + if ((rtos_qspi_flash_size_get(qspi_flash_ctx) - rtos_dfu_image_get_data_partition_addr(dfu_image_ctx)) > 0) { + addr += rtos_dfu_image_get_data_partition_addr(dfu_image_ctx); + endaddr = rtos_qspi_flash_size_get(qspi_flash_ctx); /* End of flash */ + } + break; + } + + if (addr < endaddr) { + rtos_qspi_flash_read(qspi_flash_ctx, data, addr, length); + retval = length; + } + return retval; +} + +void reboot(void) +{ + rtos_printf("Reboot initiated by tile:0x%x\n", get_local_tile_id()); + write_sswitch_reg_no_ack(get_local_tile_id(), XS1_SSWITCH_WATCHDOG_PRESCALER_WRAP_NUM, (24000 - 1)); + write_sswitch_reg_no_ack(get_local_tile_id(), XS1_SSWITCH_WATCHDOG_COUNT_NUM, 100); + write_sswitch_reg_no_ack(get_local_tile_id(), XS1_SSWITCH_WATCHDOG_PRESCALER_NUM, 0); // Reset counter + write_sswitch_reg_no_ack(get_local_tile_id(), XS1_SSWITCH_WATCHDOG_CFG_NUM, (1 << XS1_WATCHDOG_COUNT_ENABLE_SHIFT) | (1 << XS1_WATCHDOG_TRIGGER_ENABLE_SHIFT) ); + // If running DFU over I2C this function returns to the application, so that the I2C connection can be closed + #if ! appconfI2C_DFU_ENABLED + while(1) {;} +#endif +} \ No newline at end of file diff --git a/examples/ffva/src/dfu_int/dfu_common.h b/examples/ffva/src/dfu_int/dfu_common.h new file mode 100644 index 000000000..197b6605d --- /dev/null +++ b/examples/ffva/src/dfu_int/dfu_common.h @@ -0,0 +1,70 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include + +// Define the delay to wait before rebooting the device after a successful download +#define DFU_REBOOT_DELAY_MS 100 +// Define the timeout for the download operation for UA +#define DOWNLOAD_TIMEOUT_MS 10 + +// Define variable timeouts for INT to try to bring execution time down +#define DOWNLOAD_TIMEOUT_ERASE_MS 10 +#define DOWNLOAD_TIMEOUT_WRITE_MS 3 +#define DOWNLOAD_TIMEOUT_BUFFER_MS 1 + +/** + * \brief Handle a DFU request to write some data to the flash memory. + * + * This function will write \p length bytes of \p data + * to the flash memory. The correct memory partition is selected based on + * the value of \p alt. The data is written to the flash memory at the + * address specified by \p block_num. + * + * \param[in] alt Interface to identify the memory partition to write to. + * \param[in] block_num The block number used to calculate the address to write to. + * \param[in] data Buffer containing \p length valid bytes of data. + * \param[in] length The number of bytes present in \p data. + * + * \return 0 if the write operation was successful, a non-zero error value otherwise. + */ +uint32_t dfu_common_write_to_flash(uint8_t alt, + uint16_t block_num, + uint8_t const *data, + uint16_t length); + +/** + * \brief Handle a DFU request to perform a manifestation phase. + * + * This function will ensure that all the data to be written to the flash memory + * are flushed, and it resets the necessary variables to prepare for the next + * download operation. + * + * \return 0 if the write operation was successful, a non-zero error value otherwise. +*/ +uint32_t dfu_common_make_manifest(); + +/** + * \brief Handle a DFU request to read some data from the flash memory. + * + * This function will read \p length bytes of \p data + * from the flash memory. The correct memory partition is selected based on + * the value of \p alt. The data is read from the flash memory at the + * address specified by \p block_num. + * + * \param[in] alt Interface to identify the memory partition to read from. + * \param[in] block_num The block number used to calculate the address to read from. + * \param[in] data Buffer to store the data read from the memory. + * \param[in] length The number of bytes to copy to \p data. + * + * \return 0 if the write operation was successful, a non-zero error value otherwise. + */ +uint16_t dfu_common_read_from_flash(uint8_t alt, + uint16_t block_num, + uint8_t *data, + uint16_t length); + +/** + * \brief Reboot the device. + */ +void reboot(void); diff --git a/examples/ffva/src/dfu_int/dfu_servicer.c b/examples/ffva/src/dfu_int/dfu_servicer.c new file mode 100644 index 000000000..0606ad1c5 --- /dev/null +++ b/examples/ffva/src/dfu_int/dfu_servicer.c @@ -0,0 +1,217 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#define DEBUG_UNIT DFU_SERVICER +#ifndef DEBUG_PRINT_ENABLE_DFU_SERVICER +#define DEBUG_PRINT_ENABLE_DFU_SERVICER 0 +#endif +#include "debug_print.h" + +#include +#include +#include +#include + +#include "platform/platform_conf.h" +#include "servicer.h" +#include "dfu_servicer.h" + +#include "dfu_cmds.h" +#include "device_control_i2c.h" + +#include "dfu_common.h" +#include "dfu_state_machine.h" + +void dfu_servicer_init(servicer_t *servicer) +{ + #include "dfu_cmds_map.h" // Included instead of directly adding code since this file is autogenerated. + // Servicer resource info + static control_resource_info_t dfu_res_info[NUM_RESOURCES_DFU_SERVICER]; + + memset(servicer, 0, sizeof(servicer_t)); + servicer->id = DFU_CONTROLLER_SERVICER_RESID; + servicer->start_io = 0; + servicer->num_resources = NUM_RESOURCES_DFU_SERVICER; + + servicer->res_info = &dfu_res_info[0]; + // Servicer resource + servicer->res_info[0].resource = DFU_CONTROLLER_SERVICER_RESID; + servicer->res_info[0].command_map.num_commands = NUM_DFU_CONTROLLER_SERVICER_RESID_CMDS; + servicer->res_info[0].command_map.commands = dfu_controller_servicer_resid_cmd_map; +} + +void dfu_servicer(void *args) { + device_control_servicer_t servicer_ctx; + + servicer_t *servicer = (servicer_t*)args; + xassert(servicer != NULL); + + control_resid_t *resources = (control_resid_t*)pvPortMalloc(servicer->num_resources * sizeof(control_resid_t)); + for(int i=0; inum_resources; i++) + { + resources[i] = servicer->res_info[i].resource; + } + + control_ret_t dc_ret; + debug_printf("Calling device_control_servicer_register(), servicer ID %d, on tile %d, core %d.\n", servicer->id, THIS_XCORE_TILE, rtos_core_id_get()); + + dc_ret = device_control_servicer_register(&servicer_ctx, + device_control_ctxs, + 1, + resources, servicer->num_resources); + debug_printf("Out of device_control_servicer_register(), servicer ID %d, on tile %d. servicer_ctx address = 0x%x\n", servicer->id, THIS_XCORE_TILE, &servicer_ctx); + + vPortFree(resources); + + xTaskCreate( + dfu_int_state_machine, + "DFU state machine task", + RTOS_THREAD_STACK_SIZE(dfu_int_state_machine), + NULL, + uxTaskPriorityGet(NULL), // Same priority so should run after this task + NULL + ); + + for(;;){ + device_control_servicer_cmd_recv(&servicer_ctx, read_cmd, write_cmd, servicer, RTOS_OSAL_WAIT_FOREVER); + } +} + +control_ret_t dfu_servicer_read_cmd(control_resource_info_t *res_info, control_cmd_t cmd, uint8_t *payload, size_t payload_len) +{ + control_ret_t ret = CONTROL_SUCCESS; + uint8_t cmd_id = CONTROL_CMD_CLEAR_READ(cmd); + + memset(payload, 0, payload_len); + + debug_printf("dfu_servicer_read_cmd, cmd_id: %d.\n", cmd_id); + + switch (cmd_id) + { + case DFU_CONTROLLER_SERVICER_RESID_DFU_UPLOAD: + { + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_UPLOAD\n"); + size_t upload_len = dfu_int_upload(&payload[2], DFU_DATA_XFER_SIZE); + + payload[0] = upload_len & 0xFF; + payload[1] = (upload_len >> 8) & 0xFF; + // Rest of payload is filled by dfu_int_upload function + break; + } + + case DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATUS: + { + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATUS\n"); + dfu_int_get_status_packet_t retval; + dfu_int_get_status(&retval); + + uint8_t time_high, time_mid, time_low; + time_low = (uint8_t)(retval.timeout_ms & 0xFF); + time_mid = (uint8_t)((retval.timeout_ms >> 8) & 0xFF); + time_high = (uint8_t)((retval.timeout_ms >> 16) & 0xFF); + + payload[0] = retval.current_status; + payload[1] = time_low; + payload[2] = time_mid; + payload[3] = time_high; + payload[4] = retval.next_state; + + break; + } + + case DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATE: + { + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_GETSTATE\n"); + uint8_t state = dfu_int_get_state(); + payload[0] = state; + break; + } + + case DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK: + { + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK\n"); + uint16_t transferblock = dfu_int_get_transfer_block(); + + uint8_t tb_high, tb_low; + tb_low = (uint8_t)(transferblock & 0xFF); + tb_high = (uint8_t)((transferblock >> 8) & 0xFF); + + payload[0] = tb_low; + payload[1] = tb_high; + + break; + } + + case DFU_CONTROLLER_SERVICER_RESID_DFU_GETVERSION: + { + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_GETVERSION\n"); + static const uint8_t version[3] = {APP_VERSION_MAJOR, APP_VERSION_MINOR, APP_VERSION_PATCH}; + memcpy(payload, &version, sizeof(version)); + break; + } + + default: + { + debug_printf("DFU_CONTROLLER_SERVICER UNHANDLED COMMAND!!!\n"); + ret = CONTROL_BAD_COMMAND; + break; + } + } + + return ret; +} + +control_ret_t dfu_servicer_write_cmd(control_resource_info_t *res_info, control_cmd_t cmd, const uint8_t *payload, size_t payload_len) +{ + control_ret_t ret = CONTROL_SUCCESS; + + uint8_t cmd_id = CONTROL_CMD_CLEAR_READ(cmd); + debug_printf("dfu_servicer_write_cmd cmd_id %d.\n", cmd_id); + + switch (cmd_id) + { + case DFU_CONTROLLER_SERVICER_RESID_DFU_DETACH: + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_DETACH\n"); + dfu_int_detach(); + break; + + case DFU_CONTROLLER_SERVICER_RESID_DFU_DNLOAD: + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_DNLOAD\n"); + uint16_t dnload_length = payload[0] + (payload[1] << 8); + const uint8_t * dnload_data = &payload[2]; + dfu_int_download(dnload_length, dnload_data); + break; + + case DFU_CONTROLLER_SERVICER_RESID_DFU_CLRSTATUS: + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_CLRSTATUS\n"); + dfu_int_clear_status(); + break; + + case DFU_CONTROLLER_SERVICER_RESID_DFU_ABORT: + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_ABORT\n"); + dfu_int_abort(); + break; + + case DFU_CONTROLLER_SERVICER_RESID_DFU_SETALTERNATE: + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_SETALTERNATE\n"); + dfu_int_set_alternate(payload[0]); + break; + + case DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK: + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_TRANSFERBLOCK\n"); + uint16_t const transferblock = (payload[1] << 8) + payload[0]; + dfu_int_set_transfer_block(transferblock); + break; + + case DFU_CONTROLLER_SERVICER_RESID_DFU_REBOOT: + debug_printf("DFU_CONTROLLER_SERVICER_RESID_DFU_REBOOT\n"); + reboot(); + break; + + default: + debug_printf("DFU_CONTROLLER_SERVICER UNHANDLED COMMAND!!!\n"); + ret = CONTROL_BAD_COMMAND; + break; + } + + return ret; +} diff --git a/examples/ffva/src/dfu_int/dfu_servicer.h b/examples/ffva/src/dfu_int/dfu_servicer.h new file mode 100644 index 000000000..2f2e240fc --- /dev/null +++ b/examples/ffva/src/dfu_int/dfu_servicer.h @@ -0,0 +1,53 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#pragma once + +#include "servicer.h" + +#define DFU_CONTROLLER_SERVICER_RESID (240) +#define NUM_RESOURCES_DFU_SERVICER (1) // DFU servicer + +/** + * @brief DFU servicer task. + * + * This task handles DFU commands from the device control interface and relays + * them to the internal DFU INT state machine. + * + * \param args Pointer to the Servicer's state data structure + */ +void dfu_servicer(void *args); + +// Servicer initialization functions +/** + * @brief DFU servicer initialisation function. + * \param servicer Pointer to the Servicer's state data structure + */ +void dfu_servicer_init(servicer_t *servicer); + +/** + * @brief DFU servicer read command handler + * + * Handles read commands dedicated to the DFU servicer resource + * + * @param res_info Resource info of the current command + * @param cmd Command ID of this command + * @param payload Pointer to the payload that contains the write data + * @param payload_len Length in bytes of the write command payload + * @return control_ret_t CONTROL_SUCCESS if command handled successfully, + * otherwise control_ret_t error status indicating the error. + */ +control_ret_t dfu_servicer_read_cmd(control_resource_info_t *res_info, control_cmd_t cmd, uint8_t *payload, size_t payload_len); + +/** + * @brief DFU servicer write command handler + * + * Handles write commands dedicated to the DFU servicer resource + * + * @param res_info Resource info of the current command + * @param cmd Command ID of this command + * @param payload Pointer to the payload that contains the write data + * @param payload_len Length in bytes of the write command payload + * @return control_ret_t CONTROL_SUCCESS if command handled successfully, + * otherwise control_ret_t error status indicating the error. + */ +control_ret_t dfu_servicer_write_cmd(control_resource_info_t *res_info, control_cmd_t cmd, const uint8_t *payload, size_t payload_len); \ No newline at end of file diff --git a/examples/ffva/src/dfu_int/dfu_state_machine.c b/examples/ffva/src/dfu_int/dfu_state_machine.c new file mode 100644 index 000000000..ee354efdf --- /dev/null +++ b/examples/ffva/src/dfu_int/dfu_state_machine.c @@ -0,0 +1,867 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#define DEBUG_UNIT DFU_STATE_MACHINE +#ifndef DEBUG_PRINT_ENABLE_DFU_STATE_MACHINE +#define DEBUG_PRINT_ENABLE_DFU_STATE_MACHINE 0 +#endif +#include "debug_print.h" + +// Compiler includes +#include +#include +#include "xassert.h" +#include "xcore/hwtimer.h" + +// Application includes +#include "dfu_state_machine.h" +#include "dfu_common.h" + +// FreeRTOS includes +#include "FreeRTOS.h" +#include "rtos_osal.h" +#include "task.h" + +#define XCORE_MS_TO_TICKS(ms) (XS1_TIMER_KHZ * ms); + +#define CLEAR_ALL_BITS 0xFFFFFFFF +#define REQUEST_COUNTER_INDEX 1 + +// Each notification bit matches the value given to the command by Table 3.2 +// in USB-DFU v1.1 e.g. DNLOAD uses bit 1 since it has value 1. + +// DFU_DETACH is value 0, handled by servicer. +#define DFU_INT_TASK_BIT_DNLOAD 0b00000010 +#define DFU_INT_TASK_BIT_UPLOAD 0b00000100 +#define DFU_INT_TASK_BIT_GETSTATUS 0b00001000 +#define DFU_INT_TASK_BIT_CLRSTATUS 0b00010000 +// DFU_GETSTATE is value 5, handled by servicer. +#define DFU_INT_TASK_BIT_ABORT 0b00100000 +#define DFU_INT_TASK_BIT_SETALTERNATE 0b10000000 // not a DFU spec. command + +typedef struct dfu_int_dfu_data_t +{ + TaskHandle_t task_handle; + SemaphoreHandle_t upload_semaphore; + dfu_int_alt_setting_t alt_setting; + dfu_int_state_t current_state; + dfu_int_status_t current_status; + bool download_or_manifest_in_progress; + bool move_to_error; + dfu_int_status_t move_to_error_status; + uint16_t transfer_block; + uint16_t data_xfer_length; + uint16_t download_block_number; + uint8_t frag_number; + uint8_t dfu_data_buffer[DFU_SECTOR_SIZE]; + uint32_t previous_timeout_ms; + uint32_t timeout_start; +} dfu_int_dfu_data_t; + +static dfu_int_dfu_data_t dfu_data; + +/* DFU INT functions. These are called by the DFU servicer, and run on its RTOS + * task and thread of control.*/ + +void dfu_int_detach() +{ + /* + * This request is not valid in any state. + * It is non-compliant to issue a DFU_DETACH request at any point + * other than in the appIDLE state. Since we do not implement that + * state, we should move to the dfuERROR state on receipt. However, + * we will allow the user to force a reboot using this command. It + * is preferred that the user use DFU_REBOOT for this purpose. Since + * use of this command always forces a reboot, which resets the DFU + * state machine, we do not bother pushing the state machine into + * the dfuERROR state. + * + * ┌───────┐ + * DFU_DETACH │ 2 │ + * Any state ─────────────REBOOT──►│dfuIDLE│ + * └───────┘ + * + */ + debug_printf("Detach\n"); + reboot(); +} + +void dfu_int_download(uint16_t length, const uint8_t *download_data) +{ + debug_printf("Download %d bytes\n", length); + xassert(length <= DFU_DATA_XFER_SIZE); + + // frag_addr takes values [0, 128] + uint16_t frag_addr = dfu_data.frag_number * DFU_DATA_XFER_SIZE; + + // Buffer starts empty and is cleared by state machine on write + + dfu_data.data_xfer_length = length; + if (length > 0) + { + memcpy(&(dfu_data.dfu_data_buffer[frag_addr]), download_data, length); + } + // else ZLP, so end of download. Buffer is cleared by state machine on reset + + xTaskNotifyGiveIndexed(dfu_data.task_handle, REQUEST_COUNTER_INDEX); + xTaskNotify(dfu_data.task_handle, DFU_INT_TASK_BIT_DNLOAD, eSetBits); +} + +size_t dfu_int_upload(uint8_t *upload_buffer, size_t upload_buffer_length) +{ + debug_printf("Upload Start\n"); + // Immediately signal the state machine to populate the data buffer. + xTaskNotifyGiveIndexed(dfu_data.task_handle, REQUEST_COUNTER_INDEX); + xTaskNotify(dfu_data.task_handle, DFU_INT_TASK_BIT_UPLOAD, eSetBits); + // Now we wait for the state machine to populate the buffer and tell us. + xSemaphoreTake(dfu_data.upload_semaphore, RTOS_OSAL_WAIT_FOREVER); + // Eat the data. This will be padded to the length of dfu_data_buffer. + // Note - we are only using the first 64 bytes of the 256-wide data_buffer. + memcpy(upload_buffer, dfu_data.dfu_data_buffer, upload_buffer_length); + // And return the number of bytes that were actually read. + debug_printf("Upload %d bytes\n", dfu_data.data_xfer_length); + return dfu_data.data_xfer_length; +} + +void dfu_int_get_status(dfu_int_get_status_packet_t *get_status_packet) +{ + /* + * This request drives a reasonable amount of the state machine in + * download and manifestation. See the below diagram for state + * transitions. + * This function is quite verbose/explicit and that is intentional. + * Remember - this function runs on the servicer and tells the host what the + * state machine is going to do next. It doesn't actually drive the state + * machine, other than to handle the transitions to the error state by + * setting a relevant flag. The state machine handles the actual transitions + * and behaviours of those states. + * + * x + * ┌───┐ │ + * DFU_GETSTATUS│ │ ▼ + * ┌───┐ │ ┌─┴──────┐ + * DFU_GETSTATUS│ │ └►│ 10 │ + * │ ┌─┴────────────┐ │dfuERROR│ + * └►│ 9 │ └────────┘ + * │dfuUPLOAD-IDLE│ ▲ + * └──────────────┘ DFU_GETSTATUS│ + * │ + * ┌───┐ DFU_GETSTATUS ┌──────┐ │ + * DFU_GETSTATUS│ │ (block incomplete)│ ▼ │ + * │ ┌─┴─────┐ ┌────────────┴─┐ ┌────────┴┐ + * └►│ 2 │ │ 3 │ │ 4 │ + * │dfuIDLE│ │dfuDNLOAD-SYNC│ │dfuDNBUSY│ + * └───────┘ └──────┬───────┘ └─────────┘ + * ▲ │ + * ┌─────────┘ │ DFU_GETSTATUS + * │ DFU_GETSTATUS │(block complete) + * │(manifestation complete) ▼ + * ┌┴───────────────┐ ┌──────────────┐ + * │ 6 │ │ 5 │ + * │dfuMANIFEST-SYNC├─┐ │dfuDNLOAD-IDLE├─┐ + * └────────────────┘ │ └──────────────┘ │ + * │ ▲ │ + * ┌───────────┐ │ └──┘ + * │ 7 │◄┘ DFU_GETSTATUS + * │dfuMANIFEST│ DFU_GETSTATUS + * └─────────┬─┘ (manifestation incomplete) + * │ + * x──────────┘ + * DFU_GETSTATUS + * + */ + bool send_notification = true; + switch (dfu_data.current_state) + { + case DFU_INT_DFU_UPLOAD_IDLE: + case DFU_INT_DFU_IDLE: + case DFU_INT_DFU_ERROR: + case DFU_INT_DFU_DNLOAD_IDLE: + { + get_status_packet->next_state = dfu_data.current_state; + get_status_packet->current_status = dfu_data.current_status; + get_status_packet->timeout_ms = 0; + break; + } + case DFU_INT_DFU_DNBUSY: + case DFU_INT_DFU_MANIFEST: + { + /* + * If we are here, then we will have previously communicated a timeout + * to the host. Has the host respected that (in which case the elapsed + * time will be more than the previously sent timeout) or not? + */ + uint32_t current_time = get_reference_time(); + uint32_t timeout_tks = XCORE_MS_TO_TICKS(dfu_data.previous_timeout_ms); + uint32_t timeout_end = dfu_data.timeout_start + timeout_tks; + if ((timeout_end - current_time) < timeout_tks) + { + get_status_packet->next_state = DFU_INT_DFU_ERROR; + get_status_packet->current_status = dfu_data.current_status; + get_status_packet->timeout_ms = 0; + /* + * If we're in these states, then the state machine task is busy + * doing these things, and the host has bothered us too early - we + * should tell the state machine to make the transition to the error + * state. This is checked after it finishes being busy. This handles + * this transition without sending a notification - by the time the + * task reads the notification it will already be out of these + * states so will not behave the way we want it to. + */ + dfu_data.move_to_error = true; + dfu_data.move_to_error_status = DFU_INT_DFU_STATUS_ERR_STALLEDPKT; + } + else + { + /* + * The timeout has expired but we're still in these states, which + * means that we're still busy (and underestimated the time we'd + * need). Send the same timeout again, and tell the host we're going + * to remain in these states. (Very strictly, what the standard says + * we should be doing is moving back into the _SYNC states and then + * moving into the DNBUSY/MANIFEST states, but our replies to this + * will in theory look the same. The only way the host can tell the + * difference is if they issue a GETSTATE before a GETSTATUS, which + * they're not likely to do, and even then it'll just tell them + * we're still busy.) + */ + get_status_packet->next_state = dfu_data.current_state; + get_status_packet->current_status = dfu_data.current_status; + get_status_packet->timeout_ms = dfu_data.previous_timeout_ms; + } + send_notification = false; + break; + } + case DFU_INT_DFU_DNLOAD_SYNC: + { + if (dfu_data.download_or_manifest_in_progress) + { + get_status_packet->next_state = DFU_INT_DFU_DNBUSY; + get_status_packet->current_status = dfu_data.current_status; + if (dfu_data.frag_number == (DFU_NUM_FRAGMENTS - 1)) + { + if (dfu_data.download_block_number % 16 == 0) // SECTOR / PAGE + { + // On this download, we will be erasing a sector and writing + get_status_packet->timeout_ms = DOWNLOAD_TIMEOUT_ERASE_MS; + } + else + { + // On this download, we will be writing + get_status_packet->timeout_ms = DOWNLOAD_TIMEOUT_WRITE_MS; + } + } + else + { + // On this download, we will just be storing in a buffer + get_status_packet->timeout_ms = DOWNLOAD_TIMEOUT_BUFFER_MS; + } + } + else + { + get_status_packet->next_state = DFU_INT_DFU_DNLOAD_IDLE; + get_status_packet->current_status = dfu_data.current_status; + get_status_packet->timeout_ms = 0; + } + break; + } + case DFU_INT_DFU_MANIFEST_SYNC: + { + if (dfu_data.download_or_manifest_in_progress) + { + get_status_packet->next_state = DFU_INT_DFU_MANIFEST; + get_status_packet->current_status = dfu_data.current_status; + get_status_packet->timeout_ms = 0; + } + else + { + get_status_packet->next_state = DFU_INT_DFU_IDLE; + get_status_packet->current_status = dfu_data.current_status; + get_status_packet->timeout_ms = 0; + } + break; + } + default: + { + // We have no idea where we are, but we shouldn't be there. Panic. + get_status_packet->next_state = DFU_INT_DFU_ERROR; + get_status_packet->current_status = dfu_data.current_status; + get_status_packet->timeout_ms = 0; + break; + } + } + // Record the time just before we send the notification - latest we can set + dfu_data.previous_timeout_ms = get_status_packet->timeout_ms; + dfu_data.timeout_start = get_reference_time(); + if (send_notification) + { + xTaskNotifyGiveIndexed(dfu_data.task_handle, REQUEST_COUNTER_INDEX); + xTaskNotify(dfu_data.task_handle, DFU_INT_TASK_BIT_GETSTATUS, eSetBits); + } + debug_printf("Get Status: Status %d, Timeout %d, Time %d, Next State %d\n", + get_status_packet->current_status, + get_status_packet->timeout_ms, + dfu_data.timeout_start, + get_status_packet->next_state); +} + +void dfu_int_clear_status() +{ + debug_printf("Clear Status\n"); + xTaskNotifyGiveIndexed(dfu_data.task_handle, REQUEST_COUNTER_INDEX); + xTaskNotify(dfu_data.task_handle, DFU_INT_TASK_BIT_CLRSTATUS, eSetBits); +} + +dfu_int_state_t dfu_int_get_state() +{ + debug_printf("Get State: %d\n", dfu_data.current_state); + return dfu_data.current_state; +} + +void dfu_int_abort() +{ + debug_printf("Abort\n"); + xTaskNotifyGiveIndexed(dfu_data.task_handle, REQUEST_COUNTER_INDEX); + xTaskNotify(dfu_data.task_handle, DFU_INT_TASK_BIT_ABORT, eSetBits); +} + +void dfu_int_set_alternate(dfu_int_alt_setting_t alt) +{ + debug_printf("Set Alternate: %d\n", alt); + dfu_data.alt_setting = alt; + xTaskNotifyGiveIndexed(dfu_data.task_handle, REQUEST_COUNTER_INDEX); + xTaskNotify(dfu_data.task_handle, DFU_INT_TASK_BIT_SETALTERNATE, eSetBits); +} + +void dfu_int_set_transfer_block(uint16_t transferblock) +{ + debug_printf("Set Transfer Block: %d\n", transferblock); + dfu_data.transfer_block = transferblock; +} + +uint16_t dfu_int_get_transfer_block() +{ + debug_printf("Get Transfer Block: %d\n", dfu_data.transfer_block); + return dfu_data.transfer_block; +} + +/* Some readability functions */ + +static void dfu_int_reset_download_buffer() +{ + dfu_data.data_xfer_length = 0; + dfu_data.frag_number = 0; + dfu_data.download_block_number = 0; + memset(dfu_data.dfu_data_buffer, 0, DFU_SECTOR_SIZE); +} + +static void dfu_int_reset_state() +{ + dfu_data.current_state = DFU_INT_DFU_IDLE; + dfu_data.current_status = DFU_INT_DFU_STATUS_OK; + dfu_data.download_or_manifest_in_progress = false; + dfu_data.move_to_error = false; + dfu_data.move_to_error_status = DFU_INT_DFU_STATUS_OK; + dfu_int_reset_download_buffer(); +} + +static void dfu_int_error(dfu_int_status_t status) +{ + dfu_int_reset_state(); + dfu_data.current_state = DFU_INT_DFU_ERROR; + dfu_data.current_status = status; +} + +/* + * State machine function. This is a separate RTOS task. + * Has three notification boxes: "what event has occured", "how many events have + * occurred", and "extra data". "Extra data" is currently unused in favour of + * the dfu_data structure being accessed directly by the servicer task, but if + * this ever gets ported to a system where they don't have shared memory (i.e. + * all RTOS notification calls are going via an intertile context) then this + * could be used for the TRANSFERBLOCK and SETALTERNATE commands etc. - but the + * implementor would still need to work out how to handle the 64 byte download + * packet! + */ +void dfu_int_state_machine(void *args) +{ + /* Initialise semaphore and timer */ + dfu_data.upload_semaphore = xSemaphoreCreateBinary(); // Sem.s init empty + /* Initialise the state machine */ + dfu_data.task_handle = xTaskGetCurrentTaskHandle(); + dfu_data.alt_setting = DFU_INT_ALTERNATE_FACTORY; + dfu_int_reset_state(); + /* Sit in a loop and wait for mail */ + while (1) + { + uint32_t notification_value; + xTaskNotifyWait( + CLEAR_ALL_BITS, + CLEAR_ALL_BITS, + ¬ification_value, + RTOS_OSAL_WAIT_FOREVER); + + /* + * At this point, we've woken up from a notification. + * notification_value should have exactly 1 bit set, which corresponds + * to a specific request. Therefore, we can do a switch case. + * If multiple bits are set, then we've had multiple requests without + * the time to process them. Because we will have lost information about + * the order of these requests, this is bad - go to an error state. + * + * However - we should never actually need to check this! Because: + * We still can't know if we've had multiple of the same request issued + * since the last time we awoke. Therefore, we should use one of our + * notification indices as a counting semaphore - we decrement when we + * start processing, the servicer increments when we've got mail. If + * this value is ever 2, bad things happen - so we go to an error state. + * + * If this is actually a problem we can implement a message queue + * instead, but I'm trying to keep the implementation lightweight for + * now. + */ + + uint32_t counter_value = ulTaskNotifyTakeIndexed( + REQUEST_COUNTER_INDEX, + pdFALSE, + RTOS_OSAL_NO_WAIT); + + if (counter_value != 1) // If it's >1, bad. If it's 0... also bad. + { + dfu_int_error(DFU_INT_DFU_STATUS_ERR_STALLEDPKT); + continue; // Restart from top of loop + } + + switch (notification_value) + { + case DFU_INT_TASK_BIT_DNLOAD: + { + /* + * This request is valid in states dfuIDLE and dfuDNLOAD-IDLE. + * If in any other state, pushes to dfuERROR with errSTALLED-PKT. + * If in dfuIDLE and length is 0, pushes to dfuERROR. + * If in dfuIDLE and length > 0, pushes to dfuDNLOAD-SYNC. + * If in dfuDNLOAD-IDLE and length > 0, pushes to dfuDNLOAD-SYNC. + * If in dfuDNLOAD-IDLE and length is 0, pushes to dfuMANIFEST-SYNC. + * + * TODO: There is provision in the specification that if in + * dfuDNLOAD-IDLE and length is 0, but the device does not think + * that it has enough data, then we can push to dfuERROR with + * status errNOTDONE. We do not currently implement this behaviour + * in INT or in USB. + * + * Any other state + * or X + * │ ┌────────┐ + * DFU_DNLOAD │ │ 10 │ + * └───►│dfuERROR│ + * └────────┘ + * X X + * │ │ + * DFU_DNLOAD │ DFU_DNLOAD │ + * (len = 0) │ │ + * ┌─┴─────┐ DFU_DNLOAD ┌────────────┴─┐ + * │ 2 │ (len > 0) │ 3 │ + * │dfuIDLE├───────────►│dfuDNLOAD-SYNC│ + * └───────┘ └──────────────┘ + * X ▲ + * │ │ DFU_DNLOAD + * │ DFU_DNLOAD │ (len > 0) + * │ │ + * ┌─┴──────────────┐ DFU_DNLOAD ┌──────┴───────┐ + * │ 6 │ (len = 0) │ 5 │ + * │dfuMANIFEST-SYNC│◄───────────┤dfuDNLOAD-IDLE│ + * └────────────────┘ └──────────────┘ + * + */ + if (dfu_data.current_state == DFU_INT_DFU_IDLE && + dfu_data.data_xfer_length != 0) + { + // Starting a download. Set the "in progress" flag. + dfu_data.download_or_manifest_in_progress = true; + // Then move to the sync state + dfu_data.current_state = DFU_INT_DFU_DNLOAD_SYNC; + // We don't do anything else until we get a GETSTATUS + } + else if (dfu_data.current_state == DFU_INT_DFU_DNLOAD_IDLE) + { + if (dfu_data.data_xfer_length != 0) + { + // Continuing a download. Set the "in progress" flag. + dfu_data.download_or_manifest_in_progress = true; + // Then move to the sync state + dfu_data.current_state = DFU_INT_DFU_DNLOAD_SYNC; + // We don't do anything else until we get a GETSTATUS + } + else // fill_level == 0, so end of download phase + { + // Time to manifest. Set the "in progress" flag. + dfu_data.download_or_manifest_in_progress = true; + // Fully reset the download buffer, just to be neat. + dfu_int_reset_download_buffer(); + // Then move to the sync state + dfu_data.current_state = DFU_INT_DFU_MANIFEST_SYNC; + // We don't do anything else until we get a GETSTATUS + } + } + else // IDLE and len == 0, or not in IDLE or DNLOAD_IDLE + { + dfu_int_error(DFU_INT_DFU_STATUS_ERR_STALLEDPKT); + } + break; + } // end of case DFU_INT_TASK_BIT_DNLOAD - returns to top of loop + case DFU_INT_TASK_BIT_UPLOAD: + { + /* + * This request is valid in states dfuIDLE and dfuUPLOAD-IDLE. + * If in any other state, pushes to dfuERROR with errSTALLED-PKT. + * First and foremost, send a packet. + * If there is a full fragment to send, send + * it and then push to dfuUPLOAD-IDLE. + * If there is less than a full fragment to + * send, send it and then push to dfuIDLE. + * + * Any other state + * DFU_UPLOAD │ + * (len < fragment) │ DFU_UPLOAD + * ┌────────────────────────────┐ ▼ + * │ │ ┌────────┐ + * │ DFU_UPLOAD │ │ 10 │ + * │ (len = fragment) │ │dfuERROR│ + * │ ┌────┐ │ ┌────┐ └────────┘ + * │ │ │ ▼ │ │ + * ┌─┴──────────┴─┐ │ ┌─────┴─┐ │ + * │ 9 │◄─┘ │ 2 │◄─┘ + * │dfuUPLOAD-IDLE│ │dfuIDLE│ DFU_UPLOAD + * └──────────────┘ └───┬───┘ (len < fragment) + * ▲ │ + * └───────────────────────┘ + * DFU_UPLOAD + * (len = fragment) + * + */ + // First, clear the buffer + memset(dfu_data.dfu_data_buffer, 0, DFU_SECTOR_SIZE); + dfu_data.data_xfer_length = 0; + + if (dfu_data.current_state == DFU_INT_DFU_IDLE || + dfu_data.current_state == DFU_INT_DFU_UPLOAD_IDLE) + { + dfu_data.data_xfer_length = dfu_common_read_from_flash( + dfu_data.alt_setting, + dfu_data.transfer_block, + dfu_data.dfu_data_buffer, + DFU_DATA_XFER_SIZE); + + if (dfu_data.data_xfer_length < DFU_DATA_XFER_SIZE) + { + debug_printf("Fill level %d, resetting!\n", + dfu_data.data_xfer_length); + dfu_data.transfer_block = 0; + dfu_data.current_state = DFU_INT_DFU_IDLE; + } + else + { + dfu_data.transfer_block += 1; + dfu_data.current_state = DFU_INT_DFU_UPLOAD_IDLE; + } + } + else + { + dfu_int_error(DFU_INT_DFU_STATUS_ERR_STALLEDPKT); + } + /* + * The servicer is yielding until we give this, so we must give + * it back regardless of what happened. If an error occured, the + * data_buffer_fill_level will be 0, so the host _should_ stop + * trying to continue the upload process. That's the only way we can + * signal the conclusion of the upload process. + */ + xSemaphoreGive(dfu_data.upload_semaphore); + } + case DFU_INT_TASK_BIT_GETSTATUS: + { + /* + * This request drives a reasonable amount of the state machine in + * download and manifestation. See the below diagram for state + * transitions. + * This function is quite verbose/explicit and that is intentional. + * This function runs on the state machine itself, and drives + * behaviour and transitions thereof. + * + * x + * ┌───┐ │ + * DFU_GETSTATUS│ │ ▼ + * ┌───┐ │ ┌─┴──────┐ + * DFU_GETSTATUS│ │ └►│ 10 │ + * │ ┌─┴────────────┐ │dfuERROR│ + * └►│ 9 │ └────────┘ + * │dfuUPLOAD-IDLE│ ▲ + * └──────────────┘ DFU_GETSTATUS│ + * │ + * ┌───┐ DFU_GETSTATUS ┌──────┐ │ + * DFU_GETSTATUS│ │ (block incomplete)│ ▼ │ + * │ ┌─┴─────┐ ┌────────────┴─┐ ┌────────┴┐ + * └►│ 2 │ │ 3 │ │ 4 │ + * │dfuIDLE│ │dfuDNLOAD-SYNC│ │dfuDNBUSY│ + * └───────┘ └──────┬───────┘ └─────────┘ + * ▲ │ + * ┌─────────┘ │ DFU_GETSTATUS + * │ DFU_GETSTATUS │(block complete) + * │(manifestation complete) ▼ + * ┌┴───────────────┐ ┌──────────────┐ + * │ 6 │ │ 5 │ + * │dfuMANIFEST-SYNC├─┐ │dfuDNLOAD-IDLE├─┐ + * └────────────────┘ │ └──────────────┘ │ + * │ ▲ │ + * ┌───────────┐ │ └──┘ + * │ 7 │◄┘ DFU_GETSTATUS + * │dfuMANIFEST│ DFU_GETSTATUS + * └─────────┬─┘ (manifestation incomplete) + * │ + * x──────────┘ + * DFU_GETSTATUS + * + */ + switch (dfu_data.current_state) + { + case DFU_INT_DFU_UPLOAD_IDLE: + case DFU_INT_DFU_IDLE: + case DFU_INT_DFU_ERROR: + case DFU_INT_DFU_DNLOAD_IDLE: + { + // Do nothing - stay in the current state + break; + } + case DFU_INT_DFU_DNLOAD_SYNC: + { + if (dfu_data.download_or_manifest_in_progress) + { + /* + * We're in DNLOAD_SYNC and there is a download in progress. + * Therefore, we should write what's in the buffer to flash. + * While we're busy, if the host tries to talk to us again + * the servicer will handle it - if it should e.g. push us + * into an error state, the servicer will let us know. When + * we're done, we move back into DNLOAD_SYNC and clear the + * "download in progress" flag, ready to either receive + * another block or to move to manifestation. + */ + dfu_data.current_state = DFU_INT_DFU_DNBUSY; + /* + * From here on, we assume that DFU_DATA_XFER_SIZE is an + * integer factor of DFU_SECTOR_SIZE. I'm not going to + * waste cycles asserting on this, so reader beware, please + * make sure this is always the case (unless you want to do + * some horrible maths!) + */ + dfu_int_status_t retval = DFU_INT_DFU_STATUS_OK; + + if (dfu_data.frag_number == (DFU_NUM_FRAGMENTS - 1)) + { + // We've assembled a full download buffer. Write it. + retval = dfu_common_write_to_flash( + dfu_data.alt_setting, + dfu_data.download_block_number, + dfu_data.dfu_data_buffer, + DFU_SECTOR_SIZE); + memset(dfu_data.dfu_data_buffer, 0, DFU_SECTOR_SIZE); + dfu_data.frag_number = 0; + dfu_data.download_block_number += 1; + } + else + { + dfu_data.frag_number += 1; + } + dfu_data.download_or_manifest_in_progress = false; + if (dfu_data.move_to_error) + { + /* + * If this is set, then while we've been busy doing a + * download the servicer has decided that something bad + * has happened and asked us to move to an error state + * once we're done being busy. This is practically a + * deferment of the state transition from DNBUSY to + * ERROR. + */ + + dfu_int_error(dfu_data.move_to_error_status); + } + else if (retval != DFU_INT_DFU_STATUS_OK) + { + dfu_int_error(retval); + } + else + { + dfu_data.current_state = DFU_INT_DFU_DNLOAD_SYNC; + } + } + else + { + /* + * We're in DNLOAD_SYNC but a download is not in progress. + * This means that we've finished downloading this block and + * should move to DNLOAD_IDLE, ready for either more blocks + * or a zero-length-packet to continue. + */ + dfu_data.current_state = DFU_INT_DFU_DNLOAD_IDLE; + } + break; + } + case DFU_INT_DFU_MANIFEST_SYNC: + { + if (dfu_data.download_or_manifest_in_progress) + { + /* + * We're in MANIFEST_SYNC and there's a manifest in + * progress. Therefore we've just moved from DNLOAD_IDLE, + * and should manifest what we've just downloaded. Do that. + * If the host tries to talk to us, the servicer will handle + * it, and will tell us if we need to move to an error state + * as a result of that. + */ + dfu_data.current_state = DFU_INT_DFU_MANIFEST; + dfu_int_status_t retval = dfu_common_make_manifest(); + dfu_data.download_or_manifest_in_progress = false; + if (dfu_data.move_to_error) + { + /* + * If this is set, then while we've been busy doing a + * manifest the servicer has decided that something bad + * has happened and asked us to move to an error state + * once we're done being busy. This is practically a + * deferment of the state transition from MANIFEST to + * ERROR. + */ + dfu_int_error(dfu_data.move_to_error_status); + } + else if (retval != DFU_INT_DFU_STATUS_OK) + { + dfu_int_error(retval); + } + else + { + dfu_data.current_state = DFU_INT_DFU_MANIFEST_SYNC; + } + } + else + { + /* + * We're in MANIFEST_SYNC but a manifest is not in progress. + * This means that we've finished manifesting and are done! + * Should move to DFU_IDLE. + */ + dfu_data.current_state = DFU_INT_DFU_IDLE; + } + break; + } + case DFU_INT_DFU_DNBUSY: + case DFU_INT_DFU_MANIFEST: + default: + { + /* + * I don't think we can actually ever get here in these states, + * because we never yield while we're in them, but here for + * completeness. This transition is actually catered for by + * deferment using the dfu_data.move_to_error flag. + */ + + dfu_int_error(DFU_INT_DFU_STATUS_ERR_STALLEDPKT); + break; + } + } // end of switch current_state + break; + } // end of case DFU_INT_TASK_BIT_GETSTATUS - returns to top of loop + case DFU_INT_TASK_BIT_CLRSTATUS: + { + /* + * This request is valid in state dfuERROR only. + * If in any other states, pushes to dfuERROR with errSTALLED-PKT. + * If in dfuERROR, sets status to OK and pushes to dfuIDLE. + * + * Any other state + * │ + * │ DFU_CLRSTATUS + * ▼ + * ┌────────┐ + * ┌────────────────┤ 10 │ + * │ │dfuERROR│ + * DFU_CLRSTATUS │ └────────┘ + * ▼ + * ┌───────┐ + * │ 2 │ + * │dfuIDLE│ + * └───────┘ + * + */ + if (dfu_data.current_state == DFU_INT_DFU_ERROR) + { + dfu_int_reset_state(); + } + else + { + dfu_int_error(DFU_INT_DFU_STATUS_ERR_STALLEDPKT); + } + break; + } // end of case DFU_INT_TASK_BIT_CLRSTATUS - returns to top of loop + case DFU_INT_TASK_BIT_ABORT: + { + /* + * This request is valid in dfuIDLE, dfuDNLOAD-IDLE, dfuUPLOAD-IDLE. + * If in any other states, pushes to dfuERROR with errSTALLED-PKT. + * If in dfuIDLE, do nothing. + * If in dfuDNLOAD-IDLE, push to dfuIDLE. + * If in dfuUPLOAD-IDLE, push to dfuIDLE. + * + * Any other state + * │ + * │ DFU_ABORT + * ▼ + * ┌────────┐ + * │ 10 │ + * │dfuERROR│ + * ┌──────┐ └────────┘ + * │ │ + * ┌──────────────┐ ┌───┴───┐ │ + * │ 9 │ DFU_ABORT │ 2 │ │ DFU_ABORT + * │dfuUPLOAD-IDLE├──────────►│dfuIDLE│◄─┘ + * └──────────────┘ └───────┘ + * ▲ + * │ + * │ + * │ + * │ ┌──────────────┐ + * │ DFU_ABORT │ 5 │ + * └────────────────┤dfuDNLOAD-IDLE│ + * └──────────────┘ + * + */ + if (dfu_data.current_state == DFU_INT_DFU_UPLOAD_IDLE || + dfu_data.current_state == DFU_INT_DFU_DNLOAD_IDLE) + { + dfu_int_reset_state(); + } + else + { + dfu_int_error(DFU_INT_DFU_STATUS_ERR_STALLEDPKT); + } + break; + } // end of case DFU_INT_TASK_BIT_ABORT + case DFU_INT_TASK_BIT_SETALTERNATE: + { + /* + * dfu_int_reset_state() purposefully doesn't change the alternate + * setting, so we use it here, regardless of the fact the servicer + * has updated this already + * + * To match the USB implementation, this request resets the state + * machine. Therefore, set the alternate setting, and then we call + * reset_state(). Moving to error resets everything else about the + * state machine, so no need to do anything else here in that + * instance. + */ + dfu_int_reset_state(); + break; + } // end of case DFU_INT_TASK_BIT_SETALTERNATE + } // end of switch + } // end of while loop +} // end of dfu_state_machine() diff --git a/examples/ffva/src/dfu_int/dfu_state_machine.h b/examples/ffva/src/dfu_int/dfu_state_machine.h new file mode 100644 index 000000000..2c52de537 --- /dev/null +++ b/examples/ffva/src/dfu_int/dfu_state_machine.h @@ -0,0 +1,244 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +// Compiler includes +#include +#include + +// FreeRTOS includes +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "dfu_common.h" + +/** + * \brief Defines the size of the internal data buffer. Should match the size + * of the payload transmitted over device control. + */ +#define DFU_DATA_XFER_SIZE 128 +/** + * \brief Defines the size of a flash sector; used to assemble multiple payloads + * into one write operation. + */ +#define DFU_SECTOR_SIZE 4096 +/** + * \brief Defines the number of payloads required to fill one flash sector. It is + * assumed that #DFU_DATA_XFER_SIZE is an integer factor of #DFU_SECTOR_SIZE. + */ +#define DFU_NUM_FRAGMENTS (DFU_SECTOR_SIZE / DFU_DATA_XFER_SIZE) + +/** + * \enum dfu_int_alt_setting_t + * \brief Sets up identifiers for whether to target the factory or upgrade alts. + * + * Host application users will specify 0 for factory, 1 for upgrade. + * + * \var dfu_int_alt_setting_t::DFU_INT_ALTERNATE_FACTORY + * Sets to target the "factory" alt. This alt is read-only. + * \var dfu_int_alt_setting_t::DFU_INT_ALTERNATE_UPGRADE + * Sets to target the "upgrade" alt. This alt can be both read and written. + * + */ +typedef enum dfu_int_alt_setting_t +{ + DFU_INT_ALTERNATE_FACTORY, + DFU_INT_ALTERNATE_UPGRADE +} dfu_int_alt_setting_t; + +/** + * \enum dfu_int_state_t + * \brief Sets up identifiers for the different states in the DFU state machine. + * + * The names of these states and their values are derived from the USB Device + * Class Specification for Device Firmware Upgrade Version 1.1. This enum + * should not be changed, unless a specification update is issued. + * + */ +typedef enum dfu_int_state_t +{ + DFU_INT_APP_IDLE, // unused + DFU_INT_APP_DETACH, // unused + DFU_INT_DFU_IDLE, + DFU_INT_DFU_DNLOAD_SYNC, + DFU_INT_DFU_DNBUSY, + DFU_INT_DFU_DNLOAD_IDLE, + DFU_INT_DFU_MANIFEST_SYNC, + DFU_INT_DFU_MANIFEST, + DFU_INT_DFU_MANIFEST_WAIT_RESET, + DFU_INT_DFU_UPLOAD_IDLE, + DFU_INT_DFU_ERROR +} dfu_int_state_t; + +/** + * \enum dfu_int_status_t + * \brief Sets up identifiers for statuses reported by the state machine. + * + * The names of these statuses and their values are derived from the USB Device + * Class Specification for Device Firmware Upgrade Version 1.1. This enum + * should not be changed, unless a specification update is issued. The meaning + * of each of these statuses may be found in the third table in section 6.1.2 + * of the above specification. + * + */ +typedef enum dfu_int_status_t +{ + DFU_INT_DFU_STATUS_OK, + DFU_INT_DFU_STATUS_ERR_TARGET, + DFU_INT_DFU_STATUS_ERR_FILE, + DFU_INT_DFU_STATUS_ERR_WRITE, + DFU_INT_DFU_STATUS_ERR_ERASE, + DFU_INT_DFU_STATUS_ERR_CHECK_ERASED, + DFU_INT_DFU_STATUS_ERR_PROG, + DFU_INT_DFU_STATUS_ERR_VERIFY, + DFU_INT_DFU_STATUS_ERR_ADDRESS, + DFU_INT_DFU_STATUS_ERR_NOTDONE, + DFU_INT_DFU_STATUS_ERR_FIRMWARE, + DFU_INT_DFU_STATUS_ERR_VENDOR, + DFU_INT_DFU_STATUS_ERR_USBR, + DFU_INT_DFU_STATUS_ERR_POR, + DFU_INT_DFU_STATUS_ERR_UNKNOWN, + DFU_INT_DFU_STATUS_ERR_STALLEDPKT +} dfu_int_status_t; + +/** + * \struct dfu_int_get_status_packet_t + * \brief Contains necessary fields to facilitate the GETSTATUS request. + * + * \var dfu_int_get_status_packet_t::next_state + * Indicates the next state that the state machine will move into after this + * request is processed. + * \var dfu_int_get_status_packet_t::current_status + * Indicates the current status of the state machine, _before_ this request is + * processed. + * \var dfu_int_get_status_packet_t::timeout_ms + * Indicates the number of milliseconds the host should wait before attempting + * another request. + * + */ +typedef struct dfu_int_get_status_packet_t +{ + dfu_int_state_t next_state; + dfu_int_status_t current_status; + uint32_t timeout_ms; +} dfu_int_get_status_packet_t; + +/** + * \brief Sends a DFU_DETACH request to the DFU state machine. + * + * This is implemented as a device reboot after #DFU_REBOOT_DELAY_MS ms, set by + * default as 100 ms. + */ +void dfu_int_detach(); + +/** + * \brief Sends a DFU_DNLOAD request to the DFU state machine. + * + * This function will copy \p length bytes of the \p download_data buffer + * into a buffer internal to dfu_state_machine.c, before notifying the state + * machine and returning. If \p length is given as 0, the state machine will + * regard this as the end of the download process and will move to the + * manifestation phase. + * + * \param[in] length Number of valid bytes of data in \p download_data. + * \param[in] download_data Buffer containing \p length valid bytes of data. + */ +void dfu_int_download(uint16_t length, const uint8_t *download_data); + +/** + * \brief Sends a DFU_UPLOAD request to the DFU state machine. + * + * The state machine will fill \p upload_buffer with the next transfer block of + * data, and this function will then return the number of bytes written. + * Should the function return less than \p upload_buffer_length , then the + * device is signalling the end of the upload process. + * + * \param[out] upload_buffer Buffer into which to place the upload data + * \param[in] upload_buffer_length Length of \p upload_buffer in bytes + * \return size_t Number of bytes written to buffer + */ +size_t dfu_int_upload(uint8_t *upload_buffer, size_t upload_buffer_length); + +/** + * \brief Sends a DFU_GETSTATUS request to the DFU state machine. + * + * This function will populate \p get_status_packet with required information. + * This will be handled by the calling task, rather than by the asynchronous + * state machine task. The calling task will predict the next state that the + * state machine will move into. The calling task will then usually signal the + * asynchronous task to action this request. This allows an instantaneous + * resonse to this request, rather than waiting for the state machine to + * process the request - which may be a non-trivial time if the state machine + * is currently writing to flash. + * + * \param[out] get_status_packet Pointer to the structure to be populated + */ +void dfu_int_get_status(dfu_int_get_status_packet_t *get_status_packet); + +/** + * \brief Sends a DFU_CLRSTATUS request to the DFU state machine. + */ +void dfu_int_clear_status(); + +/** + * \brief Reads and returns the current state of the state machine. + * + * This request is serviced instantaneously, so long as the calling task has + * access to the current state of the state machine (which in the current + * implementation it does). + * + * \return dfu_int_state_t The current state of the state machine. + */ +dfu_int_state_t dfu_int_get_state(); + +/** + * \brief Sends a DFU_ABORT request to the DFU state machine. + */ +void dfu_int_abort(); + +/** + * \brief Sets the alternate interface used in UPLOAD and DNLOAD operations. + * + * This request will also always reset the state machine. + * + * \param[in] alt Alternate setting to change to. + */ +void dfu_int_set_alternate(dfu_int_alt_setting_t alt); + +/** + * \brief Sets the transfer block number for use in an UPLOAD operation. + * + * The DFU_UPLOAD request will return the data found at this transfer block. + * The transfer block size for this implementation is 64 bytes. + * This number will automatically increment on every successful DFU_UPLOAD. + * This number will default to 0. Therefore, to read the entire image, it is + * not necessary to first set this value. + * + * \param[in] transferblock Transfer block to use in an UPLOAD operation. + */ +void dfu_int_set_transfer_block(uint16_t transferblock); + +/** + * \brief Retrieves the current transfer block number. + * + * Strictly, this number represents the next transfer block that the UPLOAD + * operation will return. If called after issuing a DFU_UPLOAD request, it + * will represent the transfer block of the previous request plus one. + * + * \return uint16_t Current transfer block setting. + */ +uint16_t dfu_int_get_transfer_block(); + +/** + * \brief RTOS task running the DFU state machine. + * + * Task should be created before attempting to use any of the above functions. + * Initialises the state machine and then proceeds into a loop, waiting for + * notifications on index 0 to determine which request has been issued. Will + * read a value in notification index 1 to determine how many requests have + * been issued since the last time the task awoke; must be exactly 1 or the + * state machine will move to the error state. Notification index 2 is + * currently unused. + * + * \param[in] args Unused + */ +void dfu_int_state_machine(void *args); diff --git a/examples/ffva/src/fractions_1000ppm.h b/examples/ffva/src/fractions_1000ppm.h new file mode 100644 index 000000000..9c9ed1b8f --- /dev/null +++ b/examples/ffva/src/fractions_1000ppm.h @@ -0,0 +1,796 @@ +// Copyright 2023-2024 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. +static short frac_values_90[790] = { +0x1832, // Index: 0 Fraction: 25/51 = 0.4902 +0x1934, // Index: 1 Fraction: 26/53 = 0.4906 +0x1A36, // Index: 2 Fraction: 27/55 = 0.4909 +0x1B38, // Index: 3 Fraction: 28/57 = 0.4912 +0x1C3A, // Index: 4 Fraction: 29/59 = 0.4915 +0x1D3C, // Index: 5 Fraction: 30/61 = 0.4918 +0x1E3E, // Index: 6 Fraction: 31/63 = 0.4921 +0x1F40, // Index: 7 Fraction: 32/65 = 0.4923 +0x2042, // Index: 8 Fraction: 33/67 = 0.4925 +0x2144, // Index: 9 Fraction: 34/69 = 0.4928 +0x2246, // Index: 10 Fraction: 35/71 = 0.4930 +0x2348, // Index: 11 Fraction: 36/73 = 0.4932 +0x244A, // Index: 12 Fraction: 37/75 = 0.4933 +0x254C, // Index: 13 Fraction: 38/77 = 0.4935 +0x264E, // Index: 14 Fraction: 39/79 = 0.4937 +0x2750, // Index: 15 Fraction: 40/81 = 0.4938 +0x2852, // Index: 16 Fraction: 41/83 = 0.4940 +0x2954, // Index: 17 Fraction: 42/85 = 0.4941 +0x2A56, // Index: 18 Fraction: 43/87 = 0.4943 +0x2B58, // Index: 19 Fraction: 44/89 = 0.4944 +0x0001, // Index: 20 Fraction: 1/2 = 0.5000 +0x2C58, // Index: 21 Fraction: 45/89 = 0.5056 +0x2B56, // Index: 22 Fraction: 44/87 = 0.5057 +0x2A54, // Index: 23 Fraction: 43/85 = 0.5059 +0x2952, // Index: 24 Fraction: 42/83 = 0.5060 +0x2850, // Index: 25 Fraction: 41/81 = 0.5062 +0x274E, // Index: 26 Fraction: 40/79 = 0.5063 +0x264C, // Index: 27 Fraction: 39/77 = 0.5065 +0x254A, // Index: 28 Fraction: 38/75 = 0.5067 +0x2448, // Index: 29 Fraction: 37/73 = 0.5068 +0x2346, // Index: 30 Fraction: 36/71 = 0.5070 +0x2244, // Index: 31 Fraction: 35/69 = 0.5072 +0x2142, // Index: 32 Fraction: 34/67 = 0.5075 +0x2040, // Index: 33 Fraction: 33/65 = 0.5077 +0x1F3E, // Index: 34 Fraction: 32/63 = 0.5079 +0x1E3C, // Index: 35 Fraction: 31/61 = 0.5082 +0x1D3A, // Index: 36 Fraction: 30/59 = 0.5085 +0x1C38, // Index: 37 Fraction: 29/57 = 0.5088 +0x1B36, // Index: 38 Fraction: 28/55 = 0.5091 +0x1A34, // Index: 39 Fraction: 27/53 = 0.5094 +0x1932, // Index: 40 Fraction: 26/51 = 0.5098 +0x1830, // Index: 41 Fraction: 25/49 = 0.5102 +0x172E, // Index: 42 Fraction: 24/47 = 0.5106 +0x162C, // Index: 43 Fraction: 23/45 = 0.5111 +0x2C57, // Index: 44 Fraction: 45/88 = 0.5114 +0x152A, // Index: 45 Fraction: 22/43 = 0.5116 +0x2A53, // Index: 46 Fraction: 43/84 = 0.5119 +0x1428, // Index: 47 Fraction: 21/41 = 0.5122 +0x284F, // Index: 48 Fraction: 41/80 = 0.5125 +0x1326, // Index: 49 Fraction: 20/39 = 0.5128 +0x264B, // Index: 50 Fraction: 39/76 = 0.5132 +0x1224, // Index: 51 Fraction: 19/37 = 0.5135 +0x2447, // Index: 52 Fraction: 37/72 = 0.5139 +0x1122, // Index: 53 Fraction: 18/35 = 0.5143 +0x2243, // Index: 54 Fraction: 35/68 = 0.5147 +0x1020, // Index: 55 Fraction: 17/33 = 0.5152 +0x203F, // Index: 56 Fraction: 33/64 = 0.5156 +0x0F1E, // Index: 57 Fraction: 16/31 = 0.5161 +0x1E3B, // Index: 58 Fraction: 31/60 = 0.5167 +0x2D58, // Index: 59 Fraction: 46/89 = 0.5169 +0x0E1C, // Index: 60 Fraction: 15/29 = 0.5172 +0x2B54, // Index: 61 Fraction: 44/85 = 0.5176 +0x1C37, // Index: 62 Fraction: 29/56 = 0.5179 +0x2A52, // Index: 63 Fraction: 43/83 = 0.5181 +0x0D1A, // Index: 64 Fraction: 14/27 = 0.5185 +0x284E, // Index: 65 Fraction: 41/79 = 0.5190 +0x1A33, // Index: 66 Fraction: 27/52 = 0.5192 +0x274C, // Index: 67 Fraction: 40/77 = 0.5195 +0x0C18, // Index: 68 Fraction: 13/25 = 0.5200 +0x2548, // Index: 69 Fraction: 38/73 = 0.5205 +0x182F, // Index: 70 Fraction: 25/48 = 0.5208 +0x2446, // Index: 71 Fraction: 37/71 = 0.5211 +0x0B16, // Index: 72 Fraction: 12/23 = 0.5217 +0x2E59, // Index: 73 Fraction: 47/90 = 0.5222 +0x2242, // Index: 74 Fraction: 35/67 = 0.5224 +0x162B, // Index: 75 Fraction: 23/44 = 0.5227 +0x2140, // Index: 76 Fraction: 34/65 = 0.5231 +0x2C55, // Index: 77 Fraction: 45/86 = 0.5233 +0x0A14, // Index: 78 Fraction: 11/21 = 0.5238 +0x2A51, // Index: 79 Fraction: 43/82 = 0.5244 +0x1F3C, // Index: 80 Fraction: 32/61 = 0.5246 +0x1427, // Index: 81 Fraction: 21/40 = 0.5250 +0x1E3A, // Index: 82 Fraction: 31/59 = 0.5254 +0x284D, // Index: 83 Fraction: 41/78 = 0.5256 +0x0912, // Index: 84 Fraction: 10/19 = 0.5263 +0x2649, // Index: 85 Fraction: 39/74 = 0.5270 +0x1C36, // Index: 86 Fraction: 29/55 = 0.5273 +0x1223, // Index: 87 Fraction: 19/36 = 0.5278 +0x2E58, // Index: 88 Fraction: 47/89 = 0.5281 +0x1B34, // Index: 89 Fraction: 28/53 = 0.5283 +0x2445, // Index: 90 Fraction: 37/70 = 0.5286 +0x2D56, // Index: 91 Fraction: 46/87 = 0.5287 +0x0810, // Index: 92 Fraction: 9/17 = 0.5294 +0x2B52, // Index: 93 Fraction: 44/83 = 0.5301 +0x2241, // Index: 94 Fraction: 35/66 = 0.5303 +0x1930, // Index: 95 Fraction: 26/49 = 0.5306 +0x2A50, // Index: 96 Fraction: 43/81 = 0.5309 +0x101F, // Index: 97 Fraction: 17/32 = 0.5312 +0x294E, // Index: 98 Fraction: 42/79 = 0.5316 +0x182E, // Index: 99 Fraction: 25/47 = 0.5319 +0x203D, // Index: 100 Fraction: 33/62 = 0.5323 +0x284C, // Index: 101 Fraction: 41/77 = 0.5325 +0x070E, // Index: 102 Fraction: 8/15 = 0.5333 +0x2E57, // Index: 103 Fraction: 47/88 = 0.5341 +0x2648, // Index: 104 Fraction: 39/73 = 0.5342 +0x1E39, // Index: 105 Fraction: 31/58 = 0.5345 +0x162A, // Index: 106 Fraction: 23/43 = 0.5349 +0x2546, // Index: 107 Fraction: 38/71 = 0.5352 +0x0E1B, // Index: 108 Fraction: 15/28 = 0.5357 +0x2444, // Index: 109 Fraction: 37/69 = 0.5362 +0x1528, // Index: 110 Fraction: 22/41 = 0.5366 +0x1C35, // Index: 111 Fraction: 29/54 = 0.5370 +0x2342, // Index: 112 Fraction: 36/67 = 0.5373 +0x2A4F, // Index: 113 Fraction: 43/80 = 0.5375 +0x060C, // Index: 114 Fraction: 7/13 = 0.5385 +0x2F58, // Index: 115 Fraction: 48/89 = 0.5393 +0x284B, // Index: 116 Fraction: 41/76 = 0.5395 +0x213E, // Index: 117 Fraction: 34/63 = 0.5397 +0x1A31, // Index: 118 Fraction: 27/50 = 0.5400 +0x2E56, // Index: 119 Fraction: 47/87 = 0.5402 +0x1324, // Index: 120 Fraction: 20/37 = 0.5405 +0x203C, // Index: 121 Fraction: 33/61 = 0.5410 +0x2D54, // Index: 122 Fraction: 46/85 = 0.5412 +0x0C17, // Index: 123 Fraction: 13/24 = 0.5417 +0x2C52, // Index: 124 Fraction: 45/83 = 0.5422 +0x1F3A, // Index: 125 Fraction: 32/59 = 0.5424 +0x1222, // Index: 126 Fraction: 19/35 = 0.5429 +0x2B50, // Index: 127 Fraction: 44/81 = 0.5432 +0x182D, // Index: 128 Fraction: 25/46 = 0.5435 +0x1E38, // Index: 129 Fraction: 31/57 = 0.5439 +0x2443, // Index: 130 Fraction: 37/68 = 0.5441 +0x2A4E, // Index: 131 Fraction: 43/79 = 0.5443 +0x3059, // Index: 132 Fraction: 49/90 = 0.5444 +0x050A, // Index: 133 Fraction: 6/11 = 0.5455 +0x2E55, // Index: 134 Fraction: 47/86 = 0.5465 +0x284A, // Index: 135 Fraction: 41/75 = 0.5467 +0x223F, // Index: 136 Fraction: 35/64 = 0.5469 +0x1C34, // Index: 137 Fraction: 29/53 = 0.5472 +0x1629, // Index: 138 Fraction: 23/42 = 0.5476 +0x2748, // Index: 139 Fraction: 40/73 = 0.5479 +0x101E, // Index: 140 Fraction: 17/31 = 0.5484 +0x2C51, // Index: 141 Fraction: 45/82 = 0.5488 +0x1B32, // Index: 142 Fraction: 28/51 = 0.5490 +0x2646, // Index: 143 Fraction: 39/71 = 0.5493 +0x0A13, // Index: 144 Fraction: 11/20 = 0.5500 +0x3058, // Index: 145 Fraction: 49/89 = 0.5506 +0x2544, // Index: 146 Fraction: 38/69 = 0.5507 +0x1A30, // Index: 147 Fraction: 27/49 = 0.5510 +0x2A4D, // Index: 148 Fraction: 43/78 = 0.5513 +0x0F1C, // Index: 149 Fraction: 16/29 = 0.5517 +0x2442, // Index: 150 Fraction: 37/67 = 0.5522 +0x1425, // Index: 151 Fraction: 21/38 = 0.5526 +0x2E54, // Index: 152 Fraction: 47/85 = 0.5529 +0x192E, // Index: 153 Fraction: 26/47 = 0.5532 +0x1E37, // Index: 154 Fraction: 31/56 = 0.5536 +0x2340, // Index: 155 Fraction: 36/65 = 0.5538 +0x2849, // Index: 156 Fraction: 41/74 = 0.5541 +0x2D52, // Index: 157 Fraction: 46/83 = 0.5542 +0x0408, // Index: 158 Fraction: 5/9 = 0.5556 +0x3057, // Index: 159 Fraction: 49/88 = 0.5568 +0x2B4E, // Index: 160 Fraction: 44/79 = 0.5570 +0x2645, // Index: 161 Fraction: 39/70 = 0.5571 +0x213C, // Index: 162 Fraction: 34/61 = 0.5574 +0x1C33, // Index: 163 Fraction: 29/52 = 0.5577 +0x172A, // Index: 164 Fraction: 24/43 = 0.5581 +0x2A4C, // Index: 165 Fraction: 43/77 = 0.5584 +0x1221, // Index: 166 Fraction: 19/34 = 0.5588 +0x203A, // Index: 167 Fraction: 33/59 = 0.5593 +0x2E53, // Index: 168 Fraction: 47/84 = 0.5595 +0x0D18, // Index: 169 Fraction: 14/25 = 0.5600 +0x2441, // Index: 170 Fraction: 37/66 = 0.5606 +0x1628, // Index: 171 Fraction: 23/41 = 0.5610 +0x1F38, // Index: 172 Fraction: 32/57 = 0.5614 +0x2848, // Index: 173 Fraction: 41/73 = 0.5616 +0x3158, // Index: 174 Fraction: 50/89 = 0.5618 +0x080F, // Index: 175 Fraction: 9/16 = 0.5625 +0x3056, // Index: 176 Fraction: 49/87 = 0.5632 +0x2746, // Index: 177 Fraction: 40/71 = 0.5634 +0x1E36, // Index: 178 Fraction: 31/55 = 0.5636 +0x1526, // Index: 179 Fraction: 22/39 = 0.5641 +0x223D, // Index: 180 Fraction: 35/62 = 0.5645 +0x2F54, // Index: 181 Fraction: 48/85 = 0.5647 +0x0C16, // Index: 182 Fraction: 13/23 = 0.5652 +0x2A4B, // Index: 183 Fraction: 43/76 = 0.5658 +0x1D34, // Index: 184 Fraction: 30/53 = 0.5660 +0x2E52, // Index: 185 Fraction: 47/83 = 0.5663 +0x101D, // Index: 186 Fraction: 17/30 = 0.5667 +0x2542, // Index: 187 Fraction: 38/67 = 0.5672 +0x1424, // Index: 188 Fraction: 21/37 = 0.5676 +0x2D50, // Index: 189 Fraction: 46/81 = 0.5679 +0x182B, // Index: 190 Fraction: 25/44 = 0.5682 +0x1C32, // Index: 191 Fraction: 29/51 = 0.5686 +0x2039, // Index: 192 Fraction: 33/58 = 0.5690 +0x2440, // Index: 193 Fraction: 37/65 = 0.5692 +0x2847, // Index: 194 Fraction: 41/72 = 0.5694 +0x2C4E, // Index: 195 Fraction: 45/79 = 0.5696 +0x3055, // Index: 196 Fraction: 49/86 = 0.5698 +0x0306, // Index: 197 Fraction: 4/7 = 0.5714 +0x3258, // Index: 198 Fraction: 51/89 = 0.5730 +0x2E51, // Index: 199 Fraction: 47/82 = 0.5732 +0x2A4A, // Index: 200 Fraction: 43/75 = 0.5733 +0x2643, // Index: 201 Fraction: 39/68 = 0.5735 +0x223C, // Index: 202 Fraction: 35/61 = 0.5738 +0x1E35, // Index: 203 Fraction: 31/54 = 0.5741 +0x1A2E, // Index: 204 Fraction: 27/47 = 0.5745 +0x3156, // Index: 205 Fraction: 50/87 = 0.5747 +0x1627, // Index: 206 Fraction: 23/40 = 0.5750 +0x2948, // Index: 207 Fraction: 42/73 = 0.5753 +0x1220, // Index: 208 Fraction: 19/33 = 0.5758 +0x213A, // Index: 209 Fraction: 34/59 = 0.5763 +0x3054, // Index: 210 Fraction: 49/85 = 0.5765 +0x0E19, // Index: 211 Fraction: 15/26 = 0.5769 +0x2846, // Index: 212 Fraction: 41/71 = 0.5775 +0x192C, // Index: 213 Fraction: 26/45 = 0.5778 +0x243F, // Index: 214 Fraction: 37/64 = 0.5781 +0x2F52, // Index: 215 Fraction: 48/83 = 0.5783 +0x0A12, // Index: 216 Fraction: 11/19 = 0.5789 +0x3257, // Index: 217 Fraction: 51/88 = 0.5795 +0x2744, // Index: 218 Fraction: 40/69 = 0.5797 +0x1C31, // Index: 219 Fraction: 29/50 = 0.5800 +0x2E50, // Index: 220 Fraction: 47/81 = 0.5802 +0x111E, // Index: 221 Fraction: 18/31 = 0.5806 +0x2A49, // Index: 222 Fraction: 43/74 = 0.5811 +0x182A, // Index: 223 Fraction: 25/43 = 0.5814 +0x1F36, // Index: 224 Fraction: 32/55 = 0.5818 +0x2642, // Index: 225 Fraction: 39/67 = 0.5821 +0x2D4E, // Index: 226 Fraction: 46/79 = 0.5823 +0x060B, // Index: 227 Fraction: 7/12 = 0.5833 +0x3358, // Index: 228 Fraction: 52/89 = 0.5843 +0x2C4C, // Index: 229 Fraction: 45/77 = 0.5844 +0x2540, // Index: 230 Fraction: 38/65 = 0.5846 +0x1E34, // Index: 231 Fraction: 31/53 = 0.5849 +0x1728, // Index: 232 Fraction: 24/41 = 0.5854 +0x2845, // Index: 233 Fraction: 41/70 = 0.5857 +0x101C, // Index: 234 Fraction: 17/29 = 0.5862 +0x2B4A, // Index: 235 Fraction: 44/75 = 0.5867 +0x1A2D, // Index: 236 Fraction: 27/46 = 0.5870 +0x243E, // Index: 237 Fraction: 37/63 = 0.5873 +0x2E4F, // Index: 238 Fraction: 47/80 = 0.5875 +0x0910, // Index: 239 Fraction: 10/17 = 0.5882 +0x3459, // Index: 240 Fraction: 53/90 = 0.5889 +0x2A48, // Index: 241 Fraction: 43/73 = 0.5890 +0x2037, // Index: 242 Fraction: 33/56 = 0.5893 +0x1626, // Index: 243 Fraction: 23/39 = 0.5897 +0x233C, // Index: 244 Fraction: 36/61 = 0.5902 +0x3052, // Index: 245 Fraction: 49/83 = 0.5904 +0x0C15, // Index: 246 Fraction: 13/22 = 0.5909 +0x2946, // Index: 247 Fraction: 42/71 = 0.5915 +0x1C30, // Index: 248 Fraction: 29/49 = 0.5918 +0x2C4B, // Index: 249 Fraction: 45/76 = 0.5921 +0x0F1A, // Index: 250 Fraction: 16/27 = 0.5926 +0x3255, // Index: 251 Fraction: 51/86 = 0.5930 +0x223A, // Index: 252 Fraction: 35/59 = 0.5932 +0x121F, // Index: 253 Fraction: 19/32 = 0.5938 +0x2844, // Index: 254 Fraction: 41/69 = 0.5942 +0x1524, // Index: 255 Fraction: 22/37 = 0.5946 +0x2E4E, // Index: 256 Fraction: 47/79 = 0.5949 +0x1829, // Index: 257 Fraction: 25/42 = 0.5952 +0x3458, // Index: 258 Fraction: 53/89 = 0.5955 +0x1B2E, // Index: 259 Fraction: 28/47 = 0.5957 +0x1E33, // Index: 260 Fraction: 31/52 = 0.5962 +0x2138, // Index: 261 Fraction: 34/57 = 0.5965 +0x243D, // Index: 262 Fraction: 37/62 = 0.5968 +0x2742, // Index: 263 Fraction: 40/67 = 0.5970 +0x2A47, // Index: 264 Fraction: 43/72 = 0.5972 +0x2D4C, // Index: 265 Fraction: 46/77 = 0.5974 +0x3051, // Index: 266 Fraction: 49/82 = 0.5976 +0x3356, // Index: 267 Fraction: 52/87 = 0.5977 +0x0204, // Index: 268 Fraction: 3/5 = 0.6000 +0x3457, // Index: 269 Fraction: 53/88 = 0.6023 +0x3152, // Index: 270 Fraction: 50/83 = 0.6024 +0x2E4D, // Index: 271 Fraction: 47/78 = 0.6026 +0x2B48, // Index: 272 Fraction: 44/73 = 0.6027 +0x2843, // Index: 273 Fraction: 41/68 = 0.6029 +0x253E, // Index: 274 Fraction: 38/63 = 0.6032 +0x2239, // Index: 275 Fraction: 35/58 = 0.6034 +0x1F34, // Index: 276 Fraction: 32/53 = 0.6038 +0x1C2F, // Index: 277 Fraction: 29/48 = 0.6042 +0x192A, // Index: 278 Fraction: 26/43 = 0.6047 +0x3050, // Index: 279 Fraction: 49/81 = 0.6049 +0x1625, // Index: 280 Fraction: 23/38 = 0.6053 +0x2A46, // Index: 281 Fraction: 43/71 = 0.6056 +0x1320, // Index: 282 Fraction: 20/33 = 0.6061 +0x243C, // Index: 283 Fraction: 37/61 = 0.6066 +0x3558, // Index: 284 Fraction: 54/89 = 0.6067 +0x101B, // Index: 285 Fraction: 17/28 = 0.6071 +0x2F4E, // Index: 286 Fraction: 48/79 = 0.6076 +0x1E32, // Index: 287 Fraction: 31/51 = 0.6078 +0x2C49, // Index: 288 Fraction: 45/74 = 0.6081 +0x0D16, // Index: 289 Fraction: 14/23 = 0.6087 +0x3456, // Index: 290 Fraction: 53/87 = 0.6092 +0x263F, // Index: 291 Fraction: 39/64 = 0.6094 +0x1828, // Index: 292 Fraction: 25/41 = 0.6098 +0x233A, // Index: 293 Fraction: 36/59 = 0.6102 +0x2E4C, // Index: 294 Fraction: 47/77 = 0.6104 +0x0A11, // Index: 295 Fraction: 11/18 = 0.6111 +0x3354, // Index: 296 Fraction: 52/85 = 0.6118 +0x2842, // Index: 297 Fraction: 41/67 = 0.6119 +0x1D30, // Index: 298 Fraction: 30/49 = 0.6122 +0x304F, // Index: 299 Fraction: 49/80 = 0.6125 +0x121E, // Index: 300 Fraction: 19/31 = 0.6129 +0x2D4A, // Index: 301 Fraction: 46/75 = 0.6133 +0x1A2B, // Index: 302 Fraction: 27/44 = 0.6136 +0x2238, // Index: 303 Fraction: 35/57 = 0.6140 +0x2A45, // Index: 304 Fraction: 43/70 = 0.6143 +0x3252, // Index: 305 Fraction: 51/83 = 0.6145 +0x070C, // Index: 306 Fraction: 8/13 = 0.6154 +0x3455, // Index: 307 Fraction: 53/86 = 0.6163 +0x2C48, // Index: 308 Fraction: 45/73 = 0.6164 +0x243B, // Index: 309 Fraction: 37/60 = 0.6167 +0x1C2E, // Index: 310 Fraction: 29/47 = 0.6170 +0x3150, // Index: 311 Fraction: 50/81 = 0.6173 +0x1421, // Index: 312 Fraction: 21/34 = 0.6176 +0x3658, // Index: 313 Fraction: 55/89 = 0.6180 +0x2136, // Index: 314 Fraction: 34/55 = 0.6182 +0x2E4B, // Index: 315 Fraction: 47/76 = 0.6184 +0x0C14, // Index: 316 Fraction: 13/21 = 0.6190 +0x2B46, // Index: 317 Fraction: 44/71 = 0.6197 +0x1E31, // Index: 318 Fraction: 31/50 = 0.6200 +0x304E, // Index: 319 Fraction: 49/79 = 0.6203 +0x111C, // Index: 320 Fraction: 18/29 = 0.6207 +0x2841, // Index: 321 Fraction: 41/66 = 0.6212 +0x1624, // Index: 322 Fraction: 23/37 = 0.6216 +0x3251, // Index: 323 Fraction: 51/82 = 0.6220 +0x1B2C, // Index: 324 Fraction: 28/45 = 0.6222 +0x2034, // Index: 325 Fraction: 33/53 = 0.6226 +0x253C, // Index: 326 Fraction: 38/61 = 0.6230 +0x2A44, // Index: 327 Fraction: 43/69 = 0.6232 +0x2F4C, // Index: 328 Fraction: 48/77 = 0.6234 +0x3454, // Index: 329 Fraction: 53/85 = 0.6235 +0x0407, // Index: 330 Fraction: 5/8 = 0.6250 +0x3352, // Index: 331 Fraction: 52/83 = 0.6265 +0x2E4A, // Index: 332 Fraction: 47/75 = 0.6267 +0x2942, // Index: 333 Fraction: 42/67 = 0.6269 +0x243A, // Index: 334 Fraction: 37/59 = 0.6271 +0x1F32, // Index: 335 Fraction: 32/51 = 0.6275 +0x1A2A, // Index: 336 Fraction: 27/43 = 0.6279 +0x304D, // Index: 337 Fraction: 49/78 = 0.6282 +0x1522, // Index: 338 Fraction: 22/35 = 0.6286 +0x263D, // Index: 339 Fraction: 39/62 = 0.6290 +0x3758, // Index: 340 Fraction: 56/89 = 0.6292 +0x101A, // Index: 341 Fraction: 17/27 = 0.6296 +0x2D48, // Index: 342 Fraction: 46/73 = 0.6301 +0x1C2D, // Index: 343 Fraction: 29/46 = 0.6304 +0x2840, // Index: 344 Fraction: 41/65 = 0.6308 +0x3453, // Index: 345 Fraction: 53/84 = 0.6310 +0x0B12, // Index: 346 Fraction: 12/19 = 0.6316 +0x3656, // Index: 347 Fraction: 55/87 = 0.6322 +0x2A43, // Index: 348 Fraction: 43/68 = 0.6324 +0x1E30, // Index: 349 Fraction: 31/49 = 0.6327 +0x314E, // Index: 350 Fraction: 50/79 = 0.6329 +0x121D, // Index: 351 Fraction: 19/30 = 0.6333 +0x2C46, // Index: 352 Fraction: 45/71 = 0.6338 +0x1928, // Index: 353 Fraction: 26/41 = 0.6341 +0x2033, // Index: 354 Fraction: 33/52 = 0.6346 +0x273E, // Index: 355 Fraction: 40/63 = 0.6349 +0x2E49, // Index: 356 Fraction: 47/74 = 0.6351 +0x3554, // Index: 357 Fraction: 54/85 = 0.6353 +0x060A, // Index: 358 Fraction: 7/11 = 0.6364 +0x324F, // Index: 359 Fraction: 51/80 = 0.6375 +0x2B44, // Index: 360 Fraction: 44/69 = 0.6377 +0x2439, // Index: 361 Fraction: 37/58 = 0.6379 +0x1D2E, // Index: 362 Fraction: 30/47 = 0.6383 +0x3452, // Index: 363 Fraction: 53/83 = 0.6386 +0x1623, // Index: 364 Fraction: 23/36 = 0.6389 +0x263C, // Index: 365 Fraction: 39/61 = 0.6393 +0x3655, // Index: 366 Fraction: 55/86 = 0.6395 +0x0F18, // Index: 367 Fraction: 16/25 = 0.6400 +0x3858, // Index: 368 Fraction: 57/89 = 0.6404 +0x283F, // Index: 369 Fraction: 41/64 = 0.6406 +0x1826, // Index: 370 Fraction: 25/39 = 0.6410 +0x2134, // Index: 371 Fraction: 34/53 = 0.6415 +0x2A42, // Index: 372 Fraction: 43/67 = 0.6418 +0x3350, // Index: 373 Fraction: 52/81 = 0.6420 +0x080D, // Index: 374 Fraction: 9/14 = 0.6429 +0x3756, // Index: 375 Fraction: 56/87 = 0.6437 +0x2E48, // Index: 376 Fraction: 47/73 = 0.6438 +0x253A, // Index: 377 Fraction: 38/59 = 0.6441 +0x1C2C, // Index: 378 Fraction: 29/45 = 0.6444 +0x304B, // Index: 379 Fraction: 49/76 = 0.6447 +0x131E, // Index: 380 Fraction: 20/31 = 0.6452 +0x324E, // Index: 381 Fraction: 51/79 = 0.6456 +0x1E2F, // Index: 382 Fraction: 31/48 = 0.6458 +0x2940, // Index: 383 Fraction: 42/65 = 0.6462 +0x3451, // Index: 384 Fraction: 53/82 = 0.6463 +0x0A10, // Index: 385 Fraction: 11/17 = 0.6471 +0x3857, // Index: 386 Fraction: 57/88 = 0.6477 +0x2D46, // Index: 387 Fraction: 46/71 = 0.6479 +0x2235, // Index: 388 Fraction: 35/54 = 0.6481 +0x1724, // Index: 389 Fraction: 24/37 = 0.6486 +0x2438, // Index: 390 Fraction: 37/57 = 0.6491 +0x314C, // Index: 391 Fraction: 50/77 = 0.6494 +0x0C13, // Index: 392 Fraction: 13/20 = 0.6500 +0x3552, // Index: 393 Fraction: 54/83 = 0.6506 +0x283E, // Index: 394 Fraction: 41/63 = 0.6508 +0x1B2A, // Index: 395 Fraction: 28/43 = 0.6512 +0x2A41, // Index: 396 Fraction: 43/66 = 0.6515 +0x3958, // Index: 397 Fraction: 58/89 = 0.6517 +0x0E16, // Index: 398 Fraction: 15/23 = 0.6522 +0x2E47, // Index: 399 Fraction: 47/72 = 0.6528 +0x1F30, // Index: 400 Fraction: 32/49 = 0.6531 +0x304A, // Index: 401 Fraction: 49/75 = 0.6533 +0x1019, // Index: 402 Fraction: 17/26 = 0.6538 +0x3450, // Index: 403 Fraction: 53/81 = 0.6543 +0x2336, // Index: 404 Fraction: 36/55 = 0.6545 +0x3653, // Index: 405 Fraction: 55/84 = 0.6548 +0x121C, // Index: 406 Fraction: 19/29 = 0.6552 +0x3A59, // Index: 407 Fraction: 59/90 = 0.6556 +0x273C, // Index: 408 Fraction: 40/61 = 0.6557 +0x141F, // Index: 409 Fraction: 21/32 = 0.6562 +0x2B42, // Index: 410 Fraction: 44/67 = 0.6567 +0x1622, // Index: 411 Fraction: 23/35 = 0.6571 +0x2F48, // Index: 412 Fraction: 48/73 = 0.6575 +0x1825, // Index: 413 Fraction: 25/38 = 0.6579 +0x334E, // Index: 414 Fraction: 52/79 = 0.6582 +0x1A28, // Index: 415 Fraction: 27/41 = 0.6585 +0x3754, // Index: 416 Fraction: 56/85 = 0.6588 +0x1C2B, // Index: 417 Fraction: 29/44 = 0.6591 +0x1E2E, // Index: 418 Fraction: 31/47 = 0.6596 +0x2031, // Index: 419 Fraction: 33/50 = 0.6600 +0x2234, // Index: 420 Fraction: 35/53 = 0.6604 +0x2437, // Index: 421 Fraction: 37/56 = 0.6607 +0x263A, // Index: 422 Fraction: 39/59 = 0.6610 +0x283D, // Index: 423 Fraction: 41/62 = 0.6613 +0x2A40, // Index: 424 Fraction: 43/65 = 0.6615 +0x2C43, // Index: 425 Fraction: 45/68 = 0.6618 +0x2E46, // Index: 426 Fraction: 47/71 = 0.6620 +0x3049, // Index: 427 Fraction: 49/74 = 0.6622 +0x324C, // Index: 428 Fraction: 51/77 = 0.6623 +0x344F, // Index: 429 Fraction: 53/80 = 0.6625 +0x3652, // Index: 430 Fraction: 55/83 = 0.6627 +0x3855, // Index: 431 Fraction: 57/86 = 0.6628 +0x3A58, // Index: 432 Fraction: 59/89 = 0.6629 +0x0102, // Index: 433 Fraction: 2/3 = 0.6667 +0x3A57, // Index: 434 Fraction: 59/88 = 0.6705 +0x3854, // Index: 435 Fraction: 57/85 = 0.6706 +0x3651, // Index: 436 Fraction: 55/82 = 0.6707 +0x344E, // Index: 437 Fraction: 53/79 = 0.6709 +0x324B, // Index: 438 Fraction: 51/76 = 0.6711 +0x3048, // Index: 439 Fraction: 49/73 = 0.6712 +0x2E45, // Index: 440 Fraction: 47/70 = 0.6714 +0x2C42, // Index: 441 Fraction: 45/67 = 0.6716 +0x2A3F, // Index: 442 Fraction: 43/64 = 0.6719 +0x283C, // Index: 443 Fraction: 41/61 = 0.6721 +0x2639, // Index: 444 Fraction: 39/58 = 0.6724 +0x2436, // Index: 445 Fraction: 37/55 = 0.6727 +0x2233, // Index: 446 Fraction: 35/52 = 0.6731 +0x2030, // Index: 447 Fraction: 33/49 = 0.6735 +0x1E2D, // Index: 448 Fraction: 31/46 = 0.6739 +0x3B58, // Index: 449 Fraction: 60/89 = 0.6742 +0x1C2A, // Index: 450 Fraction: 29/43 = 0.6744 +0x3752, // Index: 451 Fraction: 56/83 = 0.6747 +0x1A27, // Index: 452 Fraction: 27/40 = 0.6750 +0x334C, // Index: 453 Fraction: 52/77 = 0.6753 +0x1824, // Index: 454 Fraction: 25/37 = 0.6757 +0x2F46, // Index: 455 Fraction: 48/71 = 0.6761 +0x1621, // Index: 456 Fraction: 23/34 = 0.6765 +0x2B40, // Index: 457 Fraction: 44/65 = 0.6769 +0x141E, // Index: 458 Fraction: 21/31 = 0.6774 +0x3C59, // Index: 459 Fraction: 61/90 = 0.6778 +0x273A, // Index: 460 Fraction: 40/59 = 0.6780 +0x3A56, // Index: 461 Fraction: 59/87 = 0.6782 +0x121B, // Index: 462 Fraction: 19/28 = 0.6786 +0x3650, // Index: 463 Fraction: 55/81 = 0.6790 +0x2334, // Index: 464 Fraction: 36/53 = 0.6792 +0x344D, // Index: 465 Fraction: 53/78 = 0.6795 +0x1018, // Index: 466 Fraction: 17/25 = 0.6800 +0x3047, // Index: 467 Fraction: 49/72 = 0.6806 +0x1F2E, // Index: 468 Fraction: 32/47 = 0.6809 +0x2E44, // Index: 469 Fraction: 47/69 = 0.6812 +0x0E15, // Index: 470 Fraction: 15/22 = 0.6818 +0x3954, // Index: 471 Fraction: 58/85 = 0.6824 +0x2A3E, // Index: 472 Fraction: 43/63 = 0.6825 +0x1B28, // Index: 473 Fraction: 28/41 = 0.6829 +0x283B, // Index: 474 Fraction: 41/60 = 0.6833 +0x354E, // Index: 475 Fraction: 54/79 = 0.6835 +0x0C12, // Index: 476 Fraction: 13/19 = 0.6842 +0x3148, // Index: 477 Fraction: 50/73 = 0.6849 +0x2435, // Index: 478 Fraction: 37/54 = 0.6852 +0x3C58, // Index: 479 Fraction: 61/89 = 0.6854 +0x1722, // Index: 480 Fraction: 24/35 = 0.6857 +0x3A55, // Index: 481 Fraction: 59/86 = 0.6860 +0x2232, // Index: 482 Fraction: 35/51 = 0.6863 +0x2D42, // Index: 483 Fraction: 46/67 = 0.6866 +0x3852, // Index: 484 Fraction: 57/83 = 0.6867 +0x0A0F, // Index: 485 Fraction: 11/16 = 0.6875 +0x344C, // Index: 486 Fraction: 53/77 = 0.6883 +0x293C, // Index: 487 Fraction: 42/61 = 0.6885 +0x1E2C, // Index: 488 Fraction: 31/45 = 0.6889 +0x3249, // Index: 489 Fraction: 51/74 = 0.6892 +0x131C, // Index: 490 Fraction: 20/29 = 0.6897 +0x3046, // Index: 491 Fraction: 49/71 = 0.6901 +0x1C29, // Index: 492 Fraction: 29/42 = 0.6905 +0x2536, // Index: 493 Fraction: 38/55 = 0.6909 +0x2E43, // Index: 494 Fraction: 47/68 = 0.6912 +0x3750, // Index: 495 Fraction: 56/81 = 0.6914 +0x080C, // Index: 496 Fraction: 9/13 = 0.6923 +0x3C57, // Index: 497 Fraction: 61/88 = 0.6932 +0x334A, // Index: 498 Fraction: 52/75 = 0.6933 +0x2A3D, // Index: 499 Fraction: 43/62 = 0.6935 +0x2130, // Index: 500 Fraction: 34/49 = 0.6939 +0x3A54, // Index: 501 Fraction: 59/85 = 0.6941 +0x1823, // Index: 502 Fraction: 25/36 = 0.6944 +0x283A, // Index: 503 Fraction: 41/59 = 0.6949 +0x3851, // Index: 504 Fraction: 57/82 = 0.6951 +0x0F16, // Index: 505 Fraction: 16/23 = 0.6957 +0x364E, // Index: 506 Fraction: 55/79 = 0.6962 +0x2637, // Index: 507 Fraction: 39/56 = 0.6964 +0x3D58, // Index: 508 Fraction: 62/89 = 0.6966 +0x1620, // Index: 509 Fraction: 23/33 = 0.6970 +0x344B, // Index: 510 Fraction: 53/76 = 0.6974 +0x1D2A, // Index: 511 Fraction: 30/43 = 0.6977 +0x2434, // Index: 512 Fraction: 37/53 = 0.6981 +0x2B3E, // Index: 513 Fraction: 44/63 = 0.6984 +0x3248, // Index: 514 Fraction: 51/73 = 0.6986 +0x3952, // Index: 515 Fraction: 58/83 = 0.6988 +0x0609, // Index: 516 Fraction: 7/10 = 0.7000 +0x3C56, // Index: 517 Fraction: 61/87 = 0.7011 +0x354C, // Index: 518 Fraction: 54/77 = 0.7013 +0x2E42, // Index: 519 Fraction: 47/67 = 0.7015 +0x2738, // Index: 520 Fraction: 40/57 = 0.7018 +0x202E, // Index: 521 Fraction: 33/47 = 0.7021 +0x3A53, // Index: 522 Fraction: 59/84 = 0.7024 +0x1924, // Index: 523 Fraction: 26/37 = 0.7027 +0x2C3F, // Index: 524 Fraction: 45/64 = 0.7031 +0x121A, // Index: 525 Fraction: 19/27 = 0.7037 +0x3146, // Index: 526 Fraction: 50/71 = 0.7042 +0x1E2B, // Index: 527 Fraction: 31/44 = 0.7045 +0x2A3C, // Index: 528 Fraction: 43/61 = 0.7049 +0x364D, // Index: 529 Fraction: 55/78 = 0.7051 +0x0B10, // Index: 530 Fraction: 12/17 = 0.7059 +0x344A, // Index: 531 Fraction: 53/75 = 0.7067 +0x2839, // Index: 532 Fraction: 41/58 = 0.7069 +0x1C28, // Index: 533 Fraction: 29/41 = 0.7073 +0x2D40, // Index: 534 Fraction: 46/65 = 0.7077 +0x3E58, // Index: 535 Fraction: 63/89 = 0.7079 +0x1017, // Index: 536 Fraction: 17/24 = 0.7083 +0x374E, // Index: 537 Fraction: 56/79 = 0.7089 +0x2636, // Index: 538 Fraction: 39/55 = 0.7091 +0x3C55, // Index: 539 Fraction: 61/86 = 0.7093 +0x151E, // Index: 540 Fraction: 22/31 = 0.7097 +0x3044, // Index: 541 Fraction: 49/69 = 0.7101 +0x1A25, // Index: 542 Fraction: 27/38 = 0.7105 +0x3A52, // Index: 543 Fraction: 59/83 = 0.7108 +0x1F2C, // Index: 544 Fraction: 32/45 = 0.7111 +0x2433, // Index: 545 Fraction: 37/52 = 0.7115 +0x293A, // Index: 546 Fraction: 42/59 = 0.7119 +0x2E41, // Index: 547 Fraction: 47/66 = 0.7121 +0x3348, // Index: 548 Fraction: 52/73 = 0.7123 +0x384F, // Index: 549 Fraction: 57/80 = 0.7125 +0x3D56, // Index: 550 Fraction: 62/87 = 0.7126 +0x0406, // Index: 551 Fraction: 5/7 = 0.7143 +0x3E57, // Index: 552 Fraction: 63/88 = 0.7159 +0x3950, // Index: 553 Fraction: 58/81 = 0.7160 +0x3449, // Index: 554 Fraction: 53/74 = 0.7162 +0x2F42, // Index: 555 Fraction: 48/67 = 0.7164 +0x2A3B, // Index: 556 Fraction: 43/60 = 0.7167 +0x2534, // Index: 557 Fraction: 38/53 = 0.7170 +0x202D, // Index: 558 Fraction: 33/46 = 0.7174 +0x3C54, // Index: 559 Fraction: 61/85 = 0.7176 +0x1B26, // Index: 560 Fraction: 28/39 = 0.7179 +0x3246, // Index: 561 Fraction: 51/71 = 0.7183 +0x161F, // Index: 562 Fraction: 23/32 = 0.7188 +0x3F58, // Index: 563 Fraction: 64/89 = 0.7191 +0x2838, // Index: 564 Fraction: 41/57 = 0.7193 +0x3A51, // Index: 565 Fraction: 59/82 = 0.7195 +0x1118, // Index: 566 Fraction: 18/25 = 0.7200 +0x3043, // Index: 567 Fraction: 49/68 = 0.7206 +0x1E2A, // Index: 568 Fraction: 31/43 = 0.7209 +0x2B3C, // Index: 569 Fraction: 44/61 = 0.7213 +0x384E, // Index: 570 Fraction: 57/79 = 0.7215 +0x0C11, // Index: 571 Fraction: 13/18 = 0.7222 +0x3B52, // Index: 572 Fraction: 60/83 = 0.7229 +0x2E40, // Index: 573 Fraction: 47/65 = 0.7231 +0x212E, // Index: 574 Fraction: 34/47 = 0.7234 +0x364B, // Index: 575 Fraction: 55/76 = 0.7237 +0x141C, // Index: 576 Fraction: 21/29 = 0.7241 +0x3144, // Index: 577 Fraction: 50/69 = 0.7246 +0x1C27, // Index: 578 Fraction: 29/40 = 0.7250 +0x2432, // Index: 579 Fraction: 37/51 = 0.7255 +0x2C3D, // Index: 580 Fraction: 45/62 = 0.7258 +0x3448, // Index: 581 Fraction: 53/73 = 0.7260 +0x3C53, // Index: 582 Fraction: 61/84 = 0.7262 +0x070A, // Index: 583 Fraction: 8/11 = 0.7273 +0x3A50, // Index: 584 Fraction: 59/81 = 0.7284 +0x3245, // Index: 585 Fraction: 51/70 = 0.7286 +0x2A3A, // Index: 586 Fraction: 43/59 = 0.7288 +0x222F, // Index: 587 Fraction: 35/48 = 0.7292 +0x3D54, // Index: 588 Fraction: 62/85 = 0.7294 +0x1A24, // Index: 589 Fraction: 27/37 = 0.7297 +0x2D3E, // Index: 590 Fraction: 46/63 = 0.7302 +0x4058, // Index: 591 Fraction: 65/89 = 0.7303 +0x1219, // Index: 592 Fraction: 19/26 = 0.7308 +0x3042, // Index: 593 Fraction: 49/67 = 0.7313 +0x1D28, // Index: 594 Fraction: 30/41 = 0.7317 +0x2837, // Index: 595 Fraction: 41/56 = 0.7321 +0x3346, // Index: 596 Fraction: 52/71 = 0.7324 +0x3E55, // Index: 597 Fraction: 63/86 = 0.7326 +0x0A0E, // Index: 598 Fraction: 11/15 = 0.7333 +0x394E, // Index: 599 Fraction: 58/79 = 0.7342 +0x2E3F, // Index: 600 Fraction: 47/64 = 0.7344 +0x2330, // Index: 601 Fraction: 36/49 = 0.7347 +0x3C52, // Index: 602 Fraction: 61/83 = 0.7349 +0x1821, // Index: 603 Fraction: 25/34 = 0.7353 +0x3F56, // Index: 604 Fraction: 64/87 = 0.7356 +0x2634, // Index: 605 Fraction: 39/53 = 0.7358 +0x3447, // Index: 606 Fraction: 53/72 = 0.7361 +0x0D12, // Index: 607 Fraction: 14/19 = 0.7368 +0x3A4F, // Index: 608 Fraction: 59/80 = 0.7375 +0x2C3C, // Index: 609 Fraction: 45/61 = 0.7377 +0x1E29, // Index: 610 Fraction: 31/42 = 0.7381 +0x2F40, // Index: 611 Fraction: 48/65 = 0.7385 +0x4057, // Index: 612 Fraction: 65/88 = 0.7386 +0x1016, // Index: 613 Fraction: 17/23 = 0.7391 +0x3548, // Index: 614 Fraction: 54/73 = 0.7397 +0x2431, // Index: 615 Fraction: 37/50 = 0.7400 +0x384C, // Index: 616 Fraction: 57/77 = 0.7403 +0x131A, // Index: 617 Fraction: 20/27 = 0.7407 +0x3E54, // Index: 618 Fraction: 63/85 = 0.7412 +0x2A39, // Index: 619 Fraction: 43/58 = 0.7414 +0x4158, // Index: 620 Fraction: 66/89 = 0.7416 +0x161E, // Index: 621 Fraction: 23/31 = 0.7419 +0x3041, // Index: 622 Fraction: 49/66 = 0.7424 +0x1922, // Index: 623 Fraction: 26/35 = 0.7429 +0x3649, // Index: 624 Fraction: 55/74 = 0.7432 +0x1C26, // Index: 625 Fraction: 29/39 = 0.7436 +0x3C51, // Index: 626 Fraction: 61/82 = 0.7439 +0x1F2A, // Index: 627 Fraction: 32/43 = 0.7442 +0x4259, // Index: 628 Fraction: 67/90 = 0.7444 +0x222E, // Index: 629 Fraction: 35/47 = 0.7447 +0x2532, // Index: 630 Fraction: 38/51 = 0.7451 +0x2836, // Index: 631 Fraction: 41/55 = 0.7455 +0x2B3A, // Index: 632 Fraction: 44/59 = 0.7458 +0x2E3E, // Index: 633 Fraction: 47/63 = 0.7460 +0x3142, // Index: 634 Fraction: 50/67 = 0.7463 +0x3446, // Index: 635 Fraction: 53/71 = 0.7465 +0x374A, // Index: 636 Fraction: 56/75 = 0.7467 +0x3A4E, // Index: 637 Fraction: 59/79 = 0.7468 +0x3D52, // Index: 638 Fraction: 62/83 = 0.7470 +0x4056, // Index: 639 Fraction: 65/87 = 0.7471 +0x0203, // Index: 640 Fraction: 3/4 = 0.7500 +0x4258, // Index: 641 Fraction: 67/89 = 0.7528 +0x3F54, // Index: 642 Fraction: 64/85 = 0.7529 +0x3C50, // Index: 643 Fraction: 61/81 = 0.7531 +0x394C, // Index: 644 Fraction: 58/77 = 0.7532 +0x3648, // Index: 645 Fraction: 55/73 = 0.7534 +0x3344, // Index: 646 Fraction: 52/69 = 0.7536 +0x3040, // Index: 647 Fraction: 49/65 = 0.7538 +0x2D3C, // Index: 648 Fraction: 46/61 = 0.7541 +0x2A38, // Index: 649 Fraction: 43/57 = 0.7544 +0x2734, // Index: 650 Fraction: 40/53 = 0.7547 +0x2430, // Index: 651 Fraction: 37/49 = 0.7551 +0x212C, // Index: 652 Fraction: 34/45 = 0.7556 +0x4055, // Index: 653 Fraction: 65/86 = 0.7558 +0x1E28, // Index: 654 Fraction: 31/41 = 0.7561 +0x3A4D, // Index: 655 Fraction: 59/78 = 0.7564 +0x1B24, // Index: 656 Fraction: 28/37 = 0.7568 +0x3445, // Index: 657 Fraction: 53/70 = 0.7571 +0x1820, // Index: 658 Fraction: 25/33 = 0.7576 +0x2E3D, // Index: 659 Fraction: 47/62 = 0.7581 +0x151C, // Index: 660 Fraction: 22/29 = 0.7586 +0x3E52, // Index: 661 Fraction: 63/83 = 0.7590 +0x2835, // Index: 662 Fraction: 41/54 = 0.7593 +0x3B4E, // Index: 663 Fraction: 60/79 = 0.7595 +0x1218, // Index: 664 Fraction: 19/25 = 0.7600 +0x3546, // Index: 665 Fraction: 54/71 = 0.7606 +0x222D, // Index: 666 Fraction: 35/46 = 0.7609 +0x3242, // Index: 667 Fraction: 51/67 = 0.7612 +0x4257, // Index: 668 Fraction: 67/88 = 0.7614 +0x0F14, // Index: 669 Fraction: 16/21 = 0.7619 +0x3C4F, // Index: 670 Fraction: 61/80 = 0.7625 +0x2C3A, // Index: 671 Fraction: 45/59 = 0.7627 +0x1C25, // Index: 672 Fraction: 29/38 = 0.7632 +0x2936, // Index: 673 Fraction: 42/55 = 0.7636 +0x3647, // Index: 674 Fraction: 55/72 = 0.7639 +0x4358, // Index: 675 Fraction: 68/89 = 0.7640 +0x0C10, // Index: 676 Fraction: 13/17 = 0.7647 +0x3D50, // Index: 677 Fraction: 62/81 = 0.7654 +0x303F, // Index: 678 Fraction: 49/64 = 0.7656 +0x232E, // Index: 679 Fraction: 36/47 = 0.7660 +0x3A4C, // Index: 680 Fraction: 59/77 = 0.7662 +0x161D, // Index: 681 Fraction: 23/30 = 0.7667 +0x3748, // Index: 682 Fraction: 56/73 = 0.7671 +0x202A, // Index: 683 Fraction: 33/43 = 0.7674 +0x2A37, // Index: 684 Fraction: 43/56 = 0.7679 +0x3444, // Index: 685 Fraction: 53/69 = 0.7681 +0x3E51, // Index: 686 Fraction: 63/82 = 0.7683 +0x090C, // Index: 687 Fraction: 10/13 = 0.7692 +0x4256, // Index: 688 Fraction: 67/87 = 0.7701 +0x3849, // Index: 689 Fraction: 57/74 = 0.7703 +0x2E3C, // Index: 690 Fraction: 47/61 = 0.7705 +0x242F, // Index: 691 Fraction: 37/48 = 0.7708 +0x3F52, // Index: 692 Fraction: 64/83 = 0.7711 +0x1A22, // Index: 693 Fraction: 27/35 = 0.7714 +0x2B38, // Index: 694 Fraction: 44/57 = 0.7719 +0x3C4E, // Index: 695 Fraction: 61/79 = 0.7722 +0x1015, // Index: 696 Fraction: 17/22 = 0.7727 +0x394A, // Index: 697 Fraction: 58/75 = 0.7733 +0x2834, // Index: 698 Fraction: 41/53 = 0.7736 +0x4053, // Index: 699 Fraction: 65/84 = 0.7738 +0x171E, // Index: 700 Fraction: 24/31 = 0.7742 +0x3646, // Index: 701 Fraction: 55/71 = 0.7746 +0x1E27, // Index: 702 Fraction: 31/40 = 0.7750 +0x4458, // Index: 703 Fraction: 69/89 = 0.7753 +0x2530, // Index: 704 Fraction: 38/49 = 0.7755 +0x2C39, // Index: 705 Fraction: 45/58 = 0.7759 +0x3342, // Index: 706 Fraction: 52/67 = 0.7761 +0x3A4B, // Index: 707 Fraction: 59/76 = 0.7763 +0x4154, // Index: 708 Fraction: 66/85 = 0.7765 +0x0608, // Index: 709 Fraction: 7/9 = 0.7778 +0x4255, // Index: 710 Fraction: 67/86 = 0.7791 +0x3B4C, // Index: 711 Fraction: 60/77 = 0.7792 +0x3443, // Index: 712 Fraction: 53/68 = 0.7794 +0x2D3A, // Index: 713 Fraction: 46/59 = 0.7797 +0x2631, // Index: 714 Fraction: 39/50 = 0.7800 +0x1F28, // Index: 715 Fraction: 32/41 = 0.7805 +0x3848, // Index: 716 Fraction: 57/73 = 0.7808 +0x181F, // Index: 717 Fraction: 25/32 = 0.7812 +0x4356, // Index: 718 Fraction: 68/87 = 0.7816 +0x2A36, // Index: 719 Fraction: 43/55 = 0.7818 +0x3C4D, // Index: 720 Fraction: 61/78 = 0.7821 +0x1116, // Index: 721 Fraction: 18/23 = 0.7826 +0x4052, // Index: 722 Fraction: 65/83 = 0.7831 +0x2E3B, // Index: 723 Fraction: 47/60 = 0.7833 +0x1C24, // Index: 724 Fraction: 29/37 = 0.7838 +0x4457, // Index: 725 Fraction: 69/88 = 0.7841 +0x2732, // Index: 726 Fraction: 40/51 = 0.7843 +0x3240, // Index: 727 Fraction: 51/65 = 0.7846 +0x3D4E, // Index: 728 Fraction: 62/79 = 0.7848 +0x0A0D, // Index: 729 Fraction: 11/14 = 0.7857 +0x4558, // Index: 730 Fraction: 70/89 = 0.7865 +0x3A4A, // Index: 731 Fraction: 59/75 = 0.7867 +0x2F3C, // Index: 732 Fraction: 48/61 = 0.7869 +0x242E, // Index: 733 Fraction: 37/47 = 0.7872 +0x3E4F, // Index: 734 Fraction: 63/80 = 0.7875 +0x1920, // Index: 735 Fraction: 26/33 = 0.7879 +0x4254, // Index: 736 Fraction: 67/85 = 0.7882 +0x2833, // Index: 737 Fraction: 41/52 = 0.7885 +0x3746, // Index: 738 Fraction: 56/71 = 0.7887 +0x4659, // Index: 739 Fraction: 71/90 = 0.7889 +0x0E12, // Index: 740 Fraction: 15/19 = 0.7895 +0x3F50, // Index: 741 Fraction: 64/81 = 0.7901 +0x303D, // Index: 742 Fraction: 49/62 = 0.7903 +0x212A, // Index: 743 Fraction: 34/43 = 0.7907 +0x3442, // Index: 744 Fraction: 53/67 = 0.7910 +0x1217, // Index: 745 Fraction: 19/24 = 0.7917 +0x3C4C, // Index: 746 Fraction: 61/77 = 0.7922 +0x2934, // Index: 747 Fraction: 42/53 = 0.7925 +0x4051, // Index: 748 Fraction: 65/82 = 0.7927 +0x161C, // Index: 749 Fraction: 23/29 = 0.7931 +0x313E, // Index: 750 Fraction: 50/63 = 0.7937 +0x1A21, // Index: 751 Fraction: 27/34 = 0.7941 +0x3948, // Index: 752 Fraction: 58/73 = 0.7945 +0x1E26, // Index: 753 Fraction: 31/39 = 0.7949 +0x4152, // Index: 754 Fraction: 66/83 = 0.7952 +0x222B, // Index: 755 Fraction: 35/44 = 0.7955 +0x2630, // Index: 756 Fraction: 39/49 = 0.7959 +0x2A35, // Index: 757 Fraction: 43/54 = 0.7963 +0x2E3A, // Index: 758 Fraction: 47/59 = 0.7966 +0x323F, // Index: 759 Fraction: 51/64 = 0.7969 +0x3644, // Index: 760 Fraction: 55/69 = 0.7971 +0x3A49, // Index: 761 Fraction: 59/74 = 0.7973 +0x3E4E, // Index: 762 Fraction: 63/79 = 0.7975 +0x4253, // Index: 763 Fraction: 67/84 = 0.7976 +0x4658, // Index: 764 Fraction: 71/89 = 0.7978 +0x0304, // Index: 765 Fraction: 4/5 = 0.8000 +0x4455, // Index: 766 Fraction: 69/86 = 0.8023 +0x4050, // Index: 767 Fraction: 65/81 = 0.8025 +0x3C4B, // Index: 768 Fraction: 61/76 = 0.8026 +0x3846, // Index: 769 Fraction: 57/71 = 0.8028 +0x3441, // Index: 770 Fraction: 53/66 = 0.8030 +0x303C, // Index: 771 Fraction: 49/61 = 0.8033 +0x2C37, // Index: 772 Fraction: 45/56 = 0.8036 +0x2832, // Index: 773 Fraction: 41/51 = 0.8039 +0x242D, // Index: 774 Fraction: 37/46 = 0.8043 +0x4556, // Index: 775 Fraction: 70/87 = 0.8046 +0x2028, // Index: 776 Fraction: 33/41 = 0.8049 +0x3D4C, // Index: 777 Fraction: 62/77 = 0.8052 +0x1C23, // Index: 778 Fraction: 29/36 = 0.8056 +0x3542, // Index: 779 Fraction: 54/67 = 0.8060 +0x181E, // Index: 780 Fraction: 25/31 = 0.8065 +0x4657, // Index: 781 Fraction: 71/88 = 0.8068 +0x2D38, // Index: 782 Fraction: 46/57 = 0.8070 +0x4252, // Index: 783 Fraction: 67/83 = 0.8072 +0x1419, // Index: 784 Fraction: 21/26 = 0.8077 +0x3A48, // Index: 785 Fraction: 59/73 = 0.8082 +0x252E, // Index: 786 Fraction: 38/47 = 0.8085 +0x3643, // Index: 787 Fraction: 55/68 = 0.8088 +0x4758, // Index: 788 Fraction: 72/89 = 0.8090 +0x1014, // Index: 789 Fraction: 17/21 = 0.8095 +}; diff --git a/examples/ffva/src/main.c b/examples/ffva/src/main.c index 697881bde..eb12d4053 100644 --- a/examples/ffva/src/main.c +++ b/examples/ffva/src/main.c @@ -1,4 +1,4 @@ -// Copyright 2020-2023 XMOS LIMITED. +// Copyright 2020-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include @@ -19,14 +19,25 @@ #include "app_conf.h" #include "platform/platform_init.h" #include "platform/driver_instances.h" +#include "platform/platform_conf.h" #include "usb_support.h" #include "usb_audio.h" #include "audio_pipeline.h" -#include "ww_model_runner/ww_model_runner.h" -#include "fs_support.h" +#include "dfu_servicer.h" +/* Headers used for the WW intent engine */ +#if appconfINTENT_ENABLED +#include "intent_engine.h" +#include "intent_handler.h" +#include "fs_support.h" +#include "gpi_ctrl.h" +#include "leds.h" +#endif #include "gpio_test/gpio_test.h" +/* Config headers for sw_pll */ +#include "sw_pll.h" + volatile int mic_from_usb = appconfMIC_SRC_DEFAULT; volatile int aec_ref_source = appconfAEC_REF_DEFAULT; @@ -55,6 +66,18 @@ void i2s_slave_intertile(void *args) { (int32_t*) tmp, appconfAUDIO_PIPELINE_FRAME_ADVANCE, portMAX_DELAY); + + +#if ON_TILE(I2S_TILE_NO) && appconfRECOVER_MCLK_I2S_APP_PLL + sw_pll_ctx_t* i2s_callback_args = (sw_pll_ctx_t*) args; + port_clear_buffer(i2s_callback_args->p_bclk_count); + port_in(i2s_callback_args->p_bclk_count); // Block until BCLK transition to synchronise. Will consume up to 1/64 of a LRCLK cycle + uint16_t mclk_pt = port_get_trigger_time(i2s_callback_args->p_mclk_count); // Immediately sample mclk_count + uint16_t bclk_pt = port_get_trigger_time(i2s_callback_args->p_bclk_count); // Now grab bclk_count (which won't have changed) + + sw_pll_lut_do_control(i2s_callback_args->sw_pll, mclk_pt, bclk_pt); +#endif + } } #endif @@ -139,6 +162,7 @@ void audio_pipeline_input(void *input_app_data, } } #endif + } int audio_pipeline_output(void *output_app_data, @@ -147,7 +171,6 @@ int audio_pipeline_output(void *output_app_data, size_t frame_count) { (void) output_app_data; - #if appconfI2S_ENABLED #if appconfI2S_MODE == appconfI2S_MODE_MASTER #if !appconfI2S_TDM_ENABLED @@ -188,6 +211,7 @@ int audio_pipeline_output(void *output_app_data, portMAX_DELAY); } #endif + #elif appconfI2S_MODE == appconfI2S_MODE_SLAVE /* I2S expects sample channel format */ int32_t tmp[appconfAUDIO_PIPELINE_FRAME_ADVANCE][appconfAUDIO_PIPELINE_CHANNELS]; @@ -202,6 +226,8 @@ int audio_pipeline_output(void *output_app_data, appconfI2S_OUTPUT_SLAVE_PORT, tmp, sizeof(tmp)); +#else + #error "Invalid I2S mode" #endif #endif @@ -211,11 +237,16 @@ int audio_pipeline_output(void *output_app_data, output_audio_frames, 6); #endif +#if appconfINTENT_ENABLED -#if appconfWW_ENABLED - ww_audio_send(intertile_ctx, - frame_count, - (int32_t(*)[2])output_audio_frames); + int32_t ww_samples[appconfAUDIO_PIPELINE_FRAME_ADVANCE]; + for (int j=0; j #include @@ -744,7 +744,9 @@ bool tud_audio_set_itf_cb(uint8_t rhport, { (void) rhport; uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); +#if DEBUG_PRINT_ENABLE_USB_AUDIO uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); +#endif #if AUDIO_OUTPUT_ENABLED if (itf == ITF_NUM_AUDIO_STREAMING_SPK) { @@ -774,8 +776,9 @@ bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, { (void) rhport; uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex)); +#if DEBUG_PRINT_ENABLE_USB_AUDIO uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue)); - +#endif #if AUDIO_OUTPUT_ENABLED if (itf == ITF_NUM_AUDIO_STREAMING_SPK) { spkr_interface_open = false; diff --git a/examples/ffva/src/usb/usb_dfu.c b/examples/ffva/src/usb/usb_dfu.c index b9c140aae..6a1e5d239 100644 --- a/examples/ffva/src/usb/usb_dfu.c +++ b/examples/ffva/src/usb/usb_dfu.c @@ -28,26 +28,16 @@ #include #include #include - #include "FreeRTOS.h" #include "timers.h" -#include "platform/driver_instances.h" #include "tusb.h" - -//--------------------------------------------------------------------+ -// MACRO CONSTANT TYPEDEF PROTYPES -//--------------------------------------------------------------------+ -static void reboot(void); +#include "dfu_common.h" //--------------------------------------------------------------------+ // DFU callbacks // Note: alt is used as the partition number, in order to support multiple partitions like FLASH, EEPROM, etc. //--------------------------------------------------------------------+ -static size_t total_len = 0; -static size_t bytes_avail = 0; -static uint32_t dn_base_addr = 0; - // Invoked right before tud_dfu_download_cb() (state=DFU_DNBUSY) or tud_dfu_manifest_cb() (state=DFU_MANIFEST) // Application return timeout in milliseconds (bwPollTimeout) for the next download/manifest operation. // During this period, USB host won't try to communicate with us. @@ -68,67 +58,11 @@ uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state) // Once finished flashing, application must call tud_dfu_finish_flashing() void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const* data, uint16_t length) { - rtos_printf("Received Alt %d BlockNum %d of length %d\n", alt, block_num, length); - - unsigned data_partition_base_addr = rtos_dfu_image_get_data_partition_addr(dfu_image_ctx); - switch(alt) { - default: - case 0: - tud_dfu_finish_flashing(DFU_STATUS_ERR_WRITE); - break; - case 1: - if (dn_base_addr == 0) { - total_len = 0; - dn_base_addr = rtos_dfu_image_get_upgrade_addr(dfu_image_ctx); - bytes_avail = data_partition_base_addr - dn_base_addr; - } - /* fallthrough */ - case 2: - if (dn_base_addr == 0) { - total_len = 0; - dn_base_addr = data_partition_base_addr; - bytes_avail = rtos_qspi_flash_size_get(qspi_flash_ctx) - dn_base_addr; - } - rtos_printf("Using addr 0x%x\nsize %u\n", dn_base_addr, bytes_avail); - if(length > 0) { - unsigned cur_addr = dn_base_addr + (block_num * CFG_TUD_DFU_XFER_BUFSIZE); - if((bytes_avail - total_len) >= length) { - rtos_printf("write %d at 0x%x\n", length, cur_addr); - - size_t sector_size = rtos_qspi_flash_sector_size_get(qspi_flash_ctx); - xassert(CFG_TUD_DFU_XFER_BUFSIZE == sector_size); - - uint8_t *tmp_buf = rtos_osal_malloc( sizeof(uint8_t) * sector_size); - rtos_qspi_flash_lock(qspi_flash_ctx); - { - rtos_qspi_flash_read( - qspi_flash_ctx, - tmp_buf, - cur_addr, - sector_size); - memcpy(tmp_buf, data, length); - rtos_qspi_flash_erase( - qspi_flash_ctx, - cur_addr, - sector_size); - rtos_qspi_flash_write( - qspi_flash_ctx, - (uint8_t *) tmp_buf, - cur_addr, - sector_size); - } - rtos_qspi_flash_unlock(qspi_flash_ctx); - rtos_osal_free(tmp_buf); - total_len += length; - } else { - rtos_printf("Insufficient space\n"); - tud_dfu_finish_flashing(DFU_STATUS_ERR_ADDRESS); - } - } - - tud_dfu_finish_flashing(DFU_STATUS_OK); - break; - } + dfu_status_t error_code = dfu_common_write_to_flash(alt, + block_num, + data, + length); + tud_dfu_finish_flashing(error_code); } // Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) @@ -136,23 +70,10 @@ void tud_dfu_download_cb(uint8_t alt, uint16_t block_num, uint8_t const* data, u // Once finished flashing, application must call tud_dfu_finish_flashing() void tud_dfu_manifest_cb(uint8_t alt) { - (void) alt; - rtos_printf("Download completed, enter manifestation\n"); - - /* Perform a read to ensure all writes have been flushed */ - uint32_t dummy = 0; - rtos_qspi_flash_read( - qspi_flash_ctx, - (uint8_t *)&dummy, - 0, - sizeof(dummy)); - - /* Reset download */ - dn_base_addr = 0; + (void)alt; - // flashing op for manifest is complete without error - // Application can perform checksum, should it fail, use appropriate status such as errVERIFY. - tud_dfu_finish_flashing(DFU_STATUS_OK); + dfu_state_t error_code = dfu_common_make_manifest(); + tud_dfu_finish_flashing(error_code); } // Invoked when received DFU_UPLOAD request @@ -160,40 +81,10 @@ void tud_dfu_manifest_cb(uint8_t alt) // Return the number of written bytes uint16_t tud_dfu_upload_cb(uint8_t alt, uint16_t block_num, uint8_t* data, uint16_t length) { - uint32_t endaddr = 0; - uint16_t retval = 0; - uint32_t addr = block_num * CFG_TUD_DFU_XFER_BUFSIZE; - - rtos_printf("Upload Alt %d BlockNum %d of length %d\n", alt, block_num, length); - - switch(alt) { - default: - break; - case 0: - if (rtos_dfu_image_get_factory_size(dfu_image_ctx) > 0) { - addr += rtos_dfu_image_get_factory_addr(dfu_image_ctx); - endaddr = rtos_dfu_image_get_factory_addr(dfu_image_ctx) + rtos_dfu_image_get_factory_size(dfu_image_ctx); - } - break; - case 1: - if (rtos_dfu_image_get_upgrade_size(dfu_image_ctx) > 0) { - addr += rtos_dfu_image_get_upgrade_addr(dfu_image_ctx); - endaddr = rtos_dfu_image_get_upgrade_addr(dfu_image_ctx) + rtos_dfu_image_get_upgrade_size(dfu_image_ctx); - } - break; - case 2: - if ((rtos_qspi_flash_size_get(qspi_flash_ctx) - rtos_dfu_image_get_data_partition_addr(dfu_image_ctx)) > 0) { - addr += rtos_dfu_image_get_data_partition_addr(dfu_image_ctx); - endaddr = rtos_qspi_flash_size_get(qspi_flash_ctx); /* End of flash */ - } - break; - } - - if (addr < endaddr) { - rtos_qspi_flash_read(qspi_flash_ctx, data, addr, length); - retval = length; - } - return retval; + return dfu_common_read_from_flash(alt, + block_num, + data, + length); } // Invoked when the Host has terminated a download or upload transfer @@ -209,11 +100,3 @@ void tud_dfu_detach_cb(void) rtos_printf("Host detach, we should probably reboot\n"); reboot(); } - -static void reboot(void) -{ - rtos_printf("Reboot initiated by tile:0x%x\n", get_local_tile_id()); - write_sswitch_reg_no_ack(get_local_tile_id(), XS1_SSWITCH_WATCHDOG_COUNT_NUM, 0x10000); - write_sswitch_reg_no_ack(get_local_tile_id(), XS1_SSWITCH_WATCHDOG_CFG_NUM, (1 << XS1_WATCHDOG_COUNT_ENABLE_SHIFT) | (1 << XS1_WATCHDOG_TRIGGER_ENABLE_SHIFT) ); - while(1) {;} -} diff --git a/examples/ffva/src/ww_model_runner/model_runner.c b/examples/ffva/src/ww_model_runner/model_runner.c deleted file mode 100644 index 6ce4a6bd8..000000000 --- a/examples/ffva/src/ww_model_runner/model_runner.c +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2021-2023 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - -#include -#include -#include - -#include "FreeRTOS.h" -#include "task.h" -#include "stream_buffer.h" - -#include "app_conf.h" -#include "platform/driver_instances.h" -#include "ww_model_runner/ww_model_runner.h" - -configSTACK_DEPTH_TYPE model_runner_manager_stack_size = 287; - -void model_runner_manager(void *args) -{ - StreamBufferHandle_t input_queue = (StreamBufferHandle_t)args; - - int16_t buf[appconfWW_FRAMES_PER_INFERENCE]; - - /* Perform any initialization here */ - - while (1) - { - /* Receive audio frames */ - uint8_t *buf_ptr = (uint8_t*)buf; - size_t buf_len = appconfWW_FRAMES_PER_INFERENCE * sizeof(int16_t); - do { - size_t bytes_rxed = xStreamBufferReceive(input_queue, - buf_ptr, - buf_len, - portMAX_DELAY); - buf_len -= bytes_rxed; - buf_ptr += bytes_rxed; - } while(buf_len > 0); - - /* Perform inference here */ - // rtos_printf("inference\n"); - } -} diff --git a/examples/ffva/src/ww_model_runner/ww_model_runner.c b/examples/ffva/src/ww_model_runner/ww_model_runner.c deleted file mode 100644 index 49ae7107e..000000000 --- a/examples/ffva/src/ww_model_runner/ww_model_runner.c +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2021-2023 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - -#include -#include -#include - -#include "FreeRTOS.h" -#include "task.h" -#include "stream_buffer.h" - -#include "app_conf.h" -#include "platform/driver_instances.h" -#include "ww_model_runner/ww_model_runner.h" - -#define ASR_CHANNEL (0) -#define COMMS_CHANNEL (1) - -#if appconfWW_ENABLED -extern configSTACK_DEPTH_TYPE model_runner_manager_stack_size; - -static StreamBufferHandle_t audio_stream = NULL; - -void ww_audio_send(rtos_intertile_t *intertile_ctx, - size_t frame_count, - int32_t (*processed_audio_frame)[2]) -{ - configASSERT(frame_count == appconfAUDIO_PIPELINE_FRAME_ADVANCE); - - uint16_t ww_samples[appconfAUDIO_PIPELINE_FRAME_ADVANCE]; - - for (int i = 0; i < frame_count; i++) { - ww_samples[i] = (uint16_t)(processed_audio_frame[i][ASR_CHANNEL] >> 16); - } - - if(audio_stream != NULL) { - if (xStreamBufferSend(audio_stream, ww_samples, sizeof(ww_samples), 0) != sizeof(ww_samples)) { - rtos_printf("lost output samples for ww\n"); - } - } -} - -void ww_task_create(unsigned priority) -{ - audio_stream = xStreamBufferCreate(2 * appconfAUDIO_PIPELINE_FRAME_ADVANCE, - appconfWW_FRAMES_PER_INFERENCE); - - xTaskCreate((TaskFunction_t)model_runner_manager, - "model_manager", - model_runner_manager_stack_size, - audio_stream, - uxTaskPriorityGet(NULL), - NULL); -} - -#endif diff --git a/examples/ffva/src/ww_model_runner/ww_model_runner.h b/examples/ffva/src/ww_model_runner/ww_model_runner.h deleted file mode 100644 index f55d5b2f0..000000000 --- a/examples/ffva/src/ww_model_runner/ww_model_runner.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2021-2023 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - -#ifndef WW_MODEL_RUNNER_H_ -#define WW_MODEL_RUNNER_H_ - -#include "FreeRTOS.h" - -void ww_task_create(unsigned priority); - -void ww_audio_send(rtos_intertile_t *intertile_ctx, - size_t frame_count, - int32_t (*processed_audio_frame)[2]); - -void model_runner_manager(void *args); - -#endif /* WW_MODEL_RUNNER_H_ */ diff --git a/examples/low_power_ffd/README.rst b/examples/low_power_ffd/README.rst index 319f8336e..b73bf4c5a 100644 --- a/examples/low_power_ffd/README.rst +++ b/examples/low_power_ffd/README.rst @@ -46,21 +46,11 @@ Supported Hardware and pre-requisites This example is supported on the XK_VOICE_L71 board. -On the host machine the XTC tools, version 15.2.1, must be installed and sourced. -The output should be -something like this: +Make sure that your XTC tools environment is activated. -:: - - $ xcc --version - xcc: Build 19-198606c, Oct-25-2022 - XTC version: 15.2.1 - Copyright (C) XMOS Limited 2008-2021. All Rights Reserved. - -On Windows it is highly recommended to use ``Ninja`` as the make system under -``cmake``. Not only is it a lot faster than MSVC ``nmake``, it also -works around an issue where certain path names may cause an issue with -the XMOS compiler under Windows. +It is recommended to use `Ninja` or `xmake` as the make system under Windows. +`Ninja` has been observed to be faster than `xmake`, however `xmake` comes natively with XTC tools. +This firmware has been tested with `Ninja` version v1.11.1. To install Ninja, follow these steps: @@ -110,12 +100,13 @@ The host applications will be installed at ``%USERPROFILE%\.xmos\bin``, and may Building the Firmware ********************* -Run the following commands in the root folder to build the firmware: +After having your python environment activated, run the following commands in the root folder to build the firmware: On Linux and Mac run: :: + pip install -r requirements.txt cmake -B build --toolchain xmos_cmake_toolchain/xs3a.cmake cd build make example_low_power_ffd_sensory @@ -124,6 +115,7 @@ On Windows run: :: + pip install -r requirements.txt cmake -G Ninja -B build --toolchain xmos_cmake_toolchain/xs3a.cmake cd build ninja example_low_power_ffd_sensory diff --git a/examples/low_power_ffd/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn b/examples/low_power_ffd/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn index b927e064e..b1284ff23 100644 --- a/examples/low_power_ffd/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn +++ b/examples/low_power_ffd/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn @@ -77,12 +77,10 @@ - + - - diff --git a/examples/low_power_ffd/low_power_ffd_sensory.cmake b/examples/low_power_ffd/low_power_ffd_sensory.cmake index 98570e1bd..f9a6beaf2 100644 --- a/examples/low_power_ffd/low_power_ffd_sensory.cmake +++ b/examples/low_power_ffd/low_power_ffd_sensory.cmake @@ -103,6 +103,7 @@ set(APP_COMMON_LINK_LIBRARIES sln_voice::app::ffd::ap sln_voice::app::asr::sensory rtos::drivers::clock_control + sln_voice::app::asr::device_memory ) #********************** diff --git a/examples/low_power_ffd/src/app_conf.h b/examples/low_power_ffd/src/app_conf.h index 734c0931b..3d28cfbea 100644 --- a/examples/low_power_ffd/src/app_conf.h +++ b/examples/low_power_ffd/src/app_conf.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef APP_CONF_H_ @@ -18,10 +18,10 @@ /* Application tile specifiers */ #include "platform/driver_instances.h" -#define AUDIO_PIPELINE_TILE_NO MICARRAY_TILE_NO +#define AUDIO_PIPELINE_OUTPUT_TILE_NO MICARRAY_TILE_NO #define ASR_TILE_NO FLASH_TILE_NO #define FS_TILE_NO FLASH_TILE_NO -#define WAKEWORD_TILE_NO AUDIO_PIPELINE_TILE_NO +#define WAKEWORD_TILE_NO AUDIO_PIPELINE_OUTPUT_TILE_NO /* Sensory specific settings */ #if ON_TILE(ASR_TILE_NO) @@ -67,12 +67,12 @@ #define appconfINTENT_TRANSPORT_DELAY_MS 50 #endif -#ifndef appconfINTENT_I2C_OUTPUT_ENABLED -#define appconfINTENT_I2C_OUTPUT_ENABLED 1 +#ifndef appconfINTENT_I2C_MASTER_OUTPUT_ENABLED +#define appconfINTENT_I2C_MASTER_OUTPUT_ENABLED 1 #endif -#ifndef appconfINTENT_I2C_OUTPUT_DEVICE_ADDR -#define appconfINTENT_I2C_OUTPUT_DEVICE_ADDR 0x01 +#ifndef appconfINTENT_I2C_MASTER_DEVICE_ADDR +#define appconfINTENT_I2C_MASTER_DEVICE_ADDR 0x01 #endif #ifndef appconfINTENT_UART_OUTPUT_ENABLED diff --git a/examples/low_power_ffd/src/app_conf_check.h b/examples/low_power_ffd/src/app_conf_check.h index 8663c43a4..f7e43b71e 100644 --- a/examples/low_power_ffd/src/app_conf_check.h +++ b/examples/low_power_ffd/src/app_conf_check.h @@ -1,10 +1,10 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef APP_CONF_CHECK_H_ #define APP_CONF_CHECK_H_ -#if ASR_TILE_NO == AUDIO_PIPELINE_TILE_NO +#if ASR_TILE_NO == AUDIO_PIPELINE_OUTPUT_TILE_NO #error "This application currently expects the ASR and audio pipeline to be on separate tiles." #endif diff --git a/examples/low_power_ffd/src/device_memory_impl.c b/examples/low_power_ffd/src/device_memory_impl.c deleted file mode 100644 index 680129a4c..000000000 --- a/examples/low_power_ffd/src/device_memory_impl.c +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2023 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. -#include -#include -#include - -/* System headers */ -#include -#include -#include -#include - -/* FreeRTOS headers */ -#include "FreeRTOS.h" - -/* Library headers */ -#include "rtos_printf.h" - -/* App headers */ -#include "app_conf.h" -#include "platform/driver_instances.h" -#include "device_memory.h" -#include "device_memory_impl.h" - -void asr_printf(const char * format, ...) { - va_list args; - va_start(args, format); - xcore_utils_vprintf(format, args); - va_end(args); -} - -__attribute__((fptrgroup("devmem_malloc_fptr_grp"))) -void * devmem_malloc_local(size_t size) { - //rtos_printf("devmem_malloc_local size=%d\n", size); - return pvPortMalloc(size); -} - -__attribute__((fptrgroup("devmem_free_fptr_grp"))) -void devmem_free_local(void *ptr) { - vPortFree(ptr); -} - -__attribute__((fptrgroup("devmem_read_ext_fptr_grp"))) -void devmem_read_ext_local(void *dest, const void *src, size_t n) { - //rtos_printf("devmem_read_ext_local dest=0x%x src=0x%x size=%d\n", dest, src, n); - if (IS_FLASH(src)) { - // Need to subtract off XS1_SWMEM_BASE because qspi flash driver accounts for the offset - //uint32_t s = get_reference_time(); - rtos_qspi_flash_fast_read_mode_ll(qspi_flash_ctx, (uint8_t *)dest, (unsigned)(src - XS1_SWMEM_BASE), n, qspi_fast_flash_read_transfer_raw); - //uint32_t d = get_reference_time() - s; - //printf("%d, %0.01f (us), %0.04f (M/s)\n", n, d / 100.0f, (n / 1000000.0f ) / (d / 100000000.0f)); - } else { - memcpy(dest, src, n); - } -} - -void devmem_init(devmem_manager_t *devmem_ctx) { - xassert(devmem_ctx); - devmem_ctx->malloc = devmem_malloc_local; - devmem_ctx->free = devmem_free_local; - devmem_ctx->read_ext = devmem_read_ext_local; - devmem_ctx->read_ext_async = NULL; // not supported in this application - devmem_ctx->read_ext_wait = NULL; // not supported in this application -} diff --git a/examples/low_power_ffd/src/device_memory_impl.h b/examples/low_power_ffd/src/device_memory_impl.h deleted file mode 100644 index 0822a303c..000000000 --- a/examples/low_power_ffd/src/device_memory_impl.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2023 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. -#ifndef DEVICE_MEMORY_IMPL_H -#define DEVICE_MEMORY_IMPL_H - -#include "device_memory.h" - -void devmem_init(devmem_manager_t *devmem_ctx); - -#endif // DEVICE_MEMORY_IMPL_H \ No newline at end of file diff --git a/examples/low_power_ffd/src/intent_engine/intent_engine.c b/examples/low_power_ffd/src/intent_engine/intent_engine.c index e2af1b425..2ac70139f 100644 --- a/examples/low_power_ffd/src/intent_engine/intent_engine.c +++ b/examples/low_power_ffd/src/intent_engine/intent_engine.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -274,7 +274,7 @@ void intent_engine_task(void *args) void intent_engine_ready_sync(void) { int sync = 0; -#if ON_TILE(AUDIO_PIPELINE_TILE_NO) +#if ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) size_t len = rtos_intertile_rx_len(intertile_ctx, appconfINTENT_ENGINE_READY_SYNC_PORT, RTOS_OSAL_WAIT_FOREVER); xassert(len == sizeof(sync)); rtos_intertile_rx_data(intertile_ctx, &sync, sizeof(sync)); diff --git a/examples/low_power_ffd/src/intent_engine/intent_engine_support.c b/examples/low_power_ffd/src/intent_engine/intent_engine_support.c index 995cb3893..d11b844f3 100644 --- a/examples/low_power_ffd/src/intent_engine/intent_engine_support.c +++ b/examples/low_power_ffd/src/intent_engine/intent_engine_support.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -22,7 +22,7 @@ static StreamBufferHandle_t samples_to_engine_stream_buf = 0; #endif /* ON_TILE(ASR_TILE_NO) */ -#if ON_TILE(AUDIO_PIPELINE_TILE_NO) +#if ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) void intent_engine_samples_send_remote( rtos_intertile_t *intertile, @@ -37,7 +37,7 @@ void intent_engine_samples_send_remote( sizeof(asr_sample_t) * frame_count); } -#else /* ON_TILE(AUDIO_PIPELINE_TILE_NO) */ +#else /* ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) */ static void intent_engine_intertile_samples_in_task(void *arg) { @@ -92,4 +92,4 @@ void intent_engine_intertile_task_create(uint32_t priority) NULL); } -#endif /* ON_TILE(AUDIO_PIPELINE_TILE_NO) */ +#endif /* ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) */ diff --git a/examples/low_power_ffd/src/intent_handler/intent_handler.c b/examples/low_power_ffd/src/intent_handler/intent_handler.c index 84fca4bfa..3c9dbd1ba 100644 --- a/examples/low_power_ffd/src/intent_handler/intent_handler.c +++ b/examples/low_power_ffd/src/intent_handler/intent_handler.c @@ -50,14 +50,14 @@ static void proc_keyword_res(void *args) { vTaskDelay(pdMS_TO_TICKS(appconfINTENT_TRANSPORT_DELAY_MS)); rtos_gpio_port_out(gpio_ctx_t0, p_out_wakeup, WAKEUP_LOW); } -#if appconfINTENT_I2C_OUTPUT_ENABLED +#if appconfINTENT_I2C_MASTER_OUTPUT_ENABLED i2c_res_t ret; uint32_t buf = id; size_t sent = 0; ret = rtos_i2c_master_write( i2c_master_ctx, - appconfINTENT_I2C_OUTPUT_DEVICE_ADDR, + appconfINTENT_I2C_MASTER_DEVICE_ADDR, (uint8_t*)&buf, sizeof(uint32_t), &sent, diff --git a/examples/low_power_ffd/src/main.c b/examples/low_power_ffd/src/main.c index 7b17cc03b..45335da57 100644 --- a/examples/low_power_ffd/src/main.c +++ b/examples/low_power_ffd/src/main.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* System headers */ @@ -102,7 +102,7 @@ int audio_pipeline_output(void *output_app_data, size_t ch_count, size_t frame_count) { -#if ON_TILE(AUDIO_PIPELINE_TILE_NO) +#if ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) asr_sample_t asr_buf[appconfAUDIO_PIPELINE_FRAME_ADVANCE] = {0}; @@ -145,7 +145,7 @@ int audio_pipeline_output(void *output_app_data, intent_engine_sample_push(asr_buf, frame_count); } #endif // LOW_POWER_AUDIO_BUFFER_ENABLED -#endif // ON_TILE(AUDIO_PIPELINE_TILE_NO) +#endif // ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) return AUDIO_PIPELINE_DONT_FREE_FRAME; } @@ -211,7 +211,7 @@ void startup_task(void *arg) intent_engine_create(appconfINTENT_MODEL_RUNNER_TASK_PRIORITY, q_intent); #endif -#if ON_TILE(AUDIO_PIPELINE_TILE_NO) +#if ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) // Wait until the intent engine is initialized before starting the // audio pipeline. intent_engine_ready_sync(); diff --git a/examples/low_power_ffd/src/power/low_power_audio_buffer.h b/examples/low_power_ffd/src/power/low_power_audio_buffer.h index be45e460a..7279c26cb 100644 --- a/examples/low_power_ffd/src/power/low_power_audio_buffer.h +++ b/examples/low_power_ffd/src/power/low_power_audio_buffer.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef LOW_POWER_AUDIO_BUFFER_H_ @@ -17,7 +17,7 @@ #define LOW_POWER_AUDIO_BUFFER_ENABLED ( \ appconfAUDIO_PIPELINE_BUFFER_ENABLED && \ - ON_TILE(AUDIO_PIPELINE_TILE_NO) ) + ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) ) /** * Enqueue audio samples into a ring buffer. Oldest data will be overwritten. diff --git a/examples/low_power_ffd/src/power/power_control.h b/examples/low_power_ffd/src/power/power_control.h index a23cfc538..3c0937502 100644 --- a/examples/low_power_ffd/src/power/power_control.h +++ b/examples/low_power_ffd/src/power/power_control.h @@ -1,59 +1,59 @@ -// Copyright 2022-2023 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. - -#ifndef POWER_CONTROL_H_ -#define POWER_CONTROL_H_ - -#include "app_conf.h" -#include "power_state.h" - -// Specifies the tile that is controlling the low power mode. -#define POWER_CONTROL_TILE_NO AUDIO_PIPELINE_TILE_NO - -/** - * @brief Initialize the power control task. - * - * @param priority The priority of the task. - * @param args The arguments to send to the task. - */ -void power_control_task_create(unsigned priority, void *args); - -#if ON_TILE(POWER_CONTROL_TILE_NO) - -/** - * @brief Notify that the power control task should exit the low power state. - */ -void power_control_exit_low_power(void); - -/** - * @brief Get the power control state. - * - * @returns The applied power state. - */ -power_state_t power_control_state_get(void); - -/** - * @brief Signal to the power control task that it should halt. This request - * is only acted on when operating in full power mode and the other tile - * requests low power. In this case, the application locks the device to - * full power operation. - */ -void power_control_halt(void); - -#else - -/** - * @brief Notify the power control task that the low power state has been - * requested. The power control task may accept or reject the request. - */ -void power_control_req_low_power(void); - -/** - * @brief Notify the power control task that indication of the power state - * has completed, and it is safe to proceed with the requested operation. - */ -void power_control_ind_complete(void); - -#endif - -#endif /* POWER_CONTROL_H_ */ +// Copyright 2022-2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef POWER_CONTROL_H_ +#define POWER_CONTROL_H_ + +#include "app_conf.h" +#include "power_state.h" + +// Specifies the tile that is controlling the low power mode. +#define POWER_CONTROL_TILE_NO AUDIO_PIPELINE_OUTPUT_TILE_NO + +/** + * @brief Initialize the power control task. + * + * @param priority The priority of the task. + * @param args The arguments to send to the task. + */ +void power_control_task_create(unsigned priority, void *args); + +#if ON_TILE(POWER_CONTROL_TILE_NO) + +/** + * @brief Notify that the power control task should exit the low power state. + */ +void power_control_exit_low_power(void); + +/** + * @brief Get the power control state. + * + * @returns The applied power state. + */ +power_state_t power_control_state_get(void); + +/** + * @brief Signal to the power control task that it should halt. This request + * is only acted on when operating in full power mode and the other tile + * requests low power. In this case, the application locks the device to + * full power operation. + */ +void power_control_halt(void); + +#else + +/** + * @brief Notify the power control task that the low power state has been + * requested. The power control task may accept or reject the request. + */ +void power_control_req_low_power(void); + +/** + * @brief Notify the power control task that indication of the power state + * has completed, and it is safe to proceed with the requested operation. + */ +void power_control_ind_complete(void); + +#endif + +#endif /* POWER_CONTROL_H_ */ diff --git a/examples/mic_aggregator/README.rst b/examples/mic_aggregator/README.rst index 52e817464..ca905bb46 100644 --- a/examples/mic_aggregator/README.rst +++ b/examples/mic_aggregator/README.rst @@ -2,6 +2,9 @@ PDM Microphone Aggregator Example ################################# +.. warning:: + This example is deprecated and will be moved into a separate + Application Note and may be removed in the next major release. This example provides a bridge between 16 PDM microphones to either TDM16 slave or USB Audio and targets the xcore-ai explorer board. @@ -29,25 +32,16 @@ Download the main repo and submodules using: Building the app ================ -First install and source the XTC version: 15.2.1 tools. The easiest way to source -the tools is to open the provided shortcut to ``XTC Tools 15.2.1 Command Prompt``. -Running the compiler binary ``xcc`` will produce an output like this: - -:: - - xcc --version - xcc: Build 19-198606c, Oct-25-2022 - XTC version: 15.2.1 - Copyright (C) XMOS Limited 2008-2021. All Rights Reserved. +First make sure that your XTC tools environment is activated. Linux or Mac ------------ -To build for the first time you will need to run ``cmake`` to create the -make files: +After having your python environment activated, run the following commands in the root folder to build the firmware: :: + $ pip install -r requirements.txt $ mkdir build $ cd build $ cmake --toolchain ../xmos_cmake_toolchain/xs3a.cmake .. @@ -68,10 +62,9 @@ again. Windows ------- -It is highly recommended to use ``Ninja`` as the make system under -``cmake``. Not only is it a lot faster than MSVC ``nmake``, it also -works around an issue where certain path names may cause an issue with -the XMOS compiler under windows. +It is recommended to use `Ninja` or `xmake` as the make system under Windows. +`Ninja` has been observed to be faster than `xmake`, however `xmake` comes natively with XTC tools. +This firmware has been tested with `Ninja` version v1.11.1. To install Ninja, follow these steps: @@ -84,11 +77,11 @@ To install Ninja, follow these steps: may set the path in the current command line session using something like ``set PATH=%PATH%;C:\Users\xmos\utils\ninja`` -To build for the first time you will need to run ``cmake`` to create the -make files: +After having your python environment activated, run the following commands in the root folder to build the firmware: :: + $ pip install -r requirements.txt $ md build $ cd build $ cmake -G "Ninja" --toolchain ..\xmos_cmake_toolchain\xs3a.cmake .. diff --git a/examples/mic_aggregator/mic_aggregator.cmake b/examples/mic_aggregator/mic_aggregator.cmake index 9e17835b6..fdada95f0 100644 --- a/examples/mic_aggregator/mic_aggregator.cmake +++ b/examples/mic_aggregator/mic_aggregator.cmake @@ -3,15 +3,15 @@ #********************** set(APP_SRC_PATH ${CMAKE_CURRENT_LIST_DIR}/src) -set(MIC_ARRAY_DEMO_PATH ${CMAKE_CURRENT_LIST_DIR}/../../modules/io/modules/mic_array/demos/) +set(MIC_ARRAY_DEMO_PATH ${CMAKE_CURRENT_LIST_DIR}/../../modules/io/modules/mic_array/examples/) set(PLATFORM_FILE ${APP_SRC_PATH}/XCORE-AI-EXPLORER.xn) #We make a copy of the par decimator files to avoid include clashes from the demo -set(DEMO_PAR_DECIMATOR_FILES ${MIC_ARRAY_DEMO_PATH}/demo_par_decimator/src/decimator_subtask.c - ${MIC_ARRAY_DEMO_PATH}/demo_par_decimator/src/decimator_subtask.h - ${MIC_ARRAY_DEMO_PATH}/demo_par_decimator/src/app_decimator.hpp - ${MIC_ARRAY_DEMO_PATH}/demo_par_decimator/src/app_mic_array.hpp +set(DEMO_PAR_DECIMATOR_FILES ${MIC_ARRAY_DEMO_PATH}/app_par_decimator/src/decimator_subtask.c + ${MIC_ARRAY_DEMO_PATH}/app_par_decimator/src/decimator_subtask.h + ${MIC_ARRAY_DEMO_PATH}/app_par_decimator/src/app_decimator.hpp + ${MIC_ARRAY_DEMO_PATH}/app_par_decimator/src/app_mic_array.hpp ) file(COPY ${DEMO_PAR_DECIMATOR_FILES} DESTINATION ${APP_SRC_PATH}/par_decimator) diff --git a/examples/mic_aggregator/src/XCORE-AI-EXPLORER.xn b/examples/mic_aggregator/src/XCORE-AI-EXPLORER.xn index e0f330133..bea83b533 100644 --- a/examples/mic_aggregator/src/XCORE-AI-EXPLORER.xn +++ b/examples/mic_aggregator/src/XCORE-AI-EXPLORER.xn @@ -48,13 +48,13 @@ - + - + - + @@ -111,8 +111,6 @@ - - diff --git a/examples/speech_recognition/README.rst b/examples/speech_recognition/README.rst index 6d81061f7..f2836b1f6 100644 --- a/examples/speech_recognition/README.rst +++ b/examples/speech_recognition/README.rst @@ -9,21 +9,11 @@ Supported Hardware and pre-requisites This example is supported on the XK_VOICE_L71 board. However, the XCORE-AI-EXPLORER board can be supported with a couple minor modifications. -On the host machine the XTC tools, version 15.2.1, must be installed and sourced. -The output should be -something like this: +Make sure that your XTC tools environment is activated. -:: - - $ xcc --version - xcc: Build 19-198606c, Oct-25-2022 - XTC version: 15.2.1 - Copyright (C) XMOS Limited 2008-2021. All Rights Reserved. - -On Windows it is highly recommended to use ``Ninja`` as the make system under -``cmake``. Not only is it a lot faster than MSVC ``nmake``, it also -works around an issue where certain path names may cause an issue with -the XMOS compiler under Windows. +It is recommended to use `Ninja` or `xmake` as the make system under Windows. +`Ninja` has been observed to be faster than `xmake`, however `xmake` comes natively with XTC tools. +This firmware has been tested with `Ninja` version v1.11.1. To install Ninja, follow these steps: @@ -61,27 +51,11 @@ Linux or Mac The host application, `xscope_host_endpoint`, will be installed at `/opt/xmos/bin/`, and may be moved if desired. You may wish to add this directory to your `PATH` variable. -Before running the host application, you may need to add the location of `xscope_endpoint.so` to your `LD_LIBRARY_PATH` environment variable. This environment variable will be set if you run the host application in the XTC Tools command-line environment. For more information see `Configuring the command-line environment `__. +Before running the host application, you may need to add the location of `xscope_endpoint.so` to your `LD_LIBRARY_PATH` environment variable. This environment variable will be set if you run the host application in the XTC Tools command-line environment. For more information see `Configuring the command-line environment `__. Windows ------- -It is highly recommended to use ``Ninja`` as the make system under -``cmake``. Not only is it a lot faster than MSVC ``nmake``, it also -works around an issue where certain path names may cause an issue with -the XMOS compiler under windows. - -To install Ninja, follow these steps: - -- Download ``ninja.exe`` from - https://github.com/ninja-build/ninja/releases. This firmware has been - tested with Ninja version v1.11.1. -- Ensure Ninja is on the command line path. You can add to the path - permanently by following these steps - https://www.computerhope.com/issues/ch000549.htm. Alternatively you - may set the path in the current command line session using something - like ``set PATH=%PATH%;C:\Users\xmos\utils\ninja`` - Before building the host application, you will need to add the path to the XTC Tools to your environment: :: @@ -99,17 +73,18 @@ Then build the host application: The host application, `xscope_host_endpoint.exe`, will install at `\.xmos\bin`, and may be moved if desired. You may wish to add this directory to your `PATH` variable. -Before running the host application, you may need to add the location of `xscope_endpoint.dll` to your `PATH`. This environment variable will be set if you run the host application in the XTC Tools command-line environment. For more information see `Configuring the command-line environment `__. +Before running the host application, you may need to add the location of `xscope_endpoint.dll` to your `PATH`. This environment variable will be set if you run the host application in the XTC Tools command-line environment. For more information see `Configuring the command-line environment `__. Building the Firmware ===================== -Run the following commands in the root folder to build the firmware: +After having your python environment activated, run the following commands in the root folder to build the firmware: On Linux and Mac run: :: + pip install -r requirements.txt cmake -B build --toolchain xmos_cmake_toolchain/xs3a.cmake cd build make example_asr @@ -118,6 +93,7 @@ On Windows run: :: + pip install -r requirements.txt cmake -G "Ninja" -B build --toolchain xmos_cmake_toolchain/xs3a.cmake cd build ninja example_asr @@ -138,7 +114,7 @@ Run the following command in the build folder to run the firmware: :: - xrun --xscope-realtime --xscope-port localhost:12345 example_asr.xe + xrun --xscope --xscope-port localhost:12345 example_asr.xe In a second console, run the following command in the ``examples/speech_recognition`` folder to run the host server: diff --git a/examples/speech_recognition/XCORE-AI-EXPLORER.xn b/examples/speech_recognition/XCORE-AI-EXPLORER.xn index 44e033b41..7370eee46 100644 --- a/examples/speech_recognition/XCORE-AI-EXPLORER.xn +++ b/examples/speech_recognition/XCORE-AI-EXPLORER.xn @@ -74,7 +74,7 @@ - + @@ -97,12 +97,10 @@ - + - - diff --git a/examples/speech_recognition/XK_VOICE_L71.xn b/examples/speech_recognition/XK_VOICE_L71.xn index b927e064e..d003d7e1f 100644 --- a/examples/speech_recognition/XK_VOICE_L71.xn +++ b/examples/speech_recognition/XK_VOICE_L71.xn @@ -81,8 +81,6 @@ - - diff --git a/examples/speech_recognition/asr_example/asr_example.cmake b/examples/speech_recognition/asr_example/asr_example.cmake index 716995b85..b3df35938 100644 --- a/examples/speech_recognition/asr_example/asr_example.cmake +++ b/examples/speech_recognition/asr_example/asr_example.cmake @@ -2,12 +2,13 @@ add_library(asr_example STATIC) target_sources(asr_example PRIVATE - ${SOLUTION_VOICE_ROOT_PATH}/modules/asr/device_memory.c ${CMAKE_CURRENT_LIST_DIR}/asr_example_impl.c + ${SOLUTION_VOICE_ROOT_PATH}/modules/asr/device_memory/device_memory.c ) target_include_directories(asr_example PUBLIC ${SOLUTION_VOICE_ROOT_PATH}/modules/asr + ${SOLUTION_VOICE_ROOT_PATH}/modules/asr/device_memory PRIVATE ${CMAKE_CURRENT_LIST_DIR} ) diff --git a/examples/speech_recognition/speech_recognition.cmake b/examples/speech_recognition/speech_recognition.cmake index 45e7bdf98..5d331dca8 100644 --- a/examples/speech_recognition/speech_recognition.cmake +++ b/examples/speech_recognition/speech_recognition.cmake @@ -6,8 +6,8 @@ include(${CMAKE_CURRENT_LIST_DIR}/asr_example/asr_example.cmake) #********************** # Gather Sources #********************** -file(GLOB_RECURSE APP_SOURCES - ${CMAKE_CURRENT_LIST_DIR}/src/*.xc +file(GLOB_RECURSE APP_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/src/*.xc ${CMAKE_CURRENT_LIST_DIR}/src/*.c ) set(APP_INCLUDES @@ -99,7 +99,7 @@ add_custom_target(flash_app_example_asr # Create run and debug targets #********************** add_custom_target(run_example_asr - COMMAND xrun --xscope-realtime --xscope-port ${XSCOPE_PORT} example_asr.xe + COMMAND xrun --xscope --xscope-port ${XSCOPE_PORT} example_asr.xe DEPENDS example_asr COMMENT "Run application" diff --git a/examples/speech_recognition/src/process_file.c b/examples/speech_recognition/src/process_file.c index f939d23ab..95f140f3c 100644 --- a/examples/speech_recognition/src/process_file.c +++ b/examples/speech_recognition/src/process_file.c @@ -6,6 +6,7 @@ #include #include +#include #include "app_conf.h" #include "asr.h" @@ -65,7 +66,7 @@ void process_file() { // Validate input wav file if(get_wav_header_details(&file, &header_struct, &header_size) != 0){ printf("Error: error in get_wav_header_details()\n"); - _Exit(1); + xassert(0); } assert(header_struct.bit_depth == 16); assert(header_struct.num_channels == MAX_CHANNELS); @@ -116,5 +117,5 @@ void process_file() { asr_release(asr_port); xscope_close_all_files(); - _Exit(0); + exit(0); // Note: exit syscall can cause issues with tools XTC 15.3.0 if called from both tiles } diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 7b365c437..ffdab11c7 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -11,11 +11,7 @@ add_subdirectory(rtos) if(${CMAKE_SYSTEM_NAME} STREQUAL XCORE_XS3A) ## Need to guard so host targets will not be built add_subdirectory(voice) - add_subdirectory(inferencing) - - ## The following alias is added to support in intermediate version of fwk_voick - ## This can be removed once fwk_voice is updated to use the new, core::lib_tflite_micro alias - add_library(sdk::inferencing::lib_tflite_micro ALIAS inferencing_tflite_micro) + add_subdirectory(sw_pll/lib_sw_pll) endif() ## Add additional modules diff --git a/modules/asr/CMakeLists.txt b/modules/asr/CMakeLists.txt index 8ca16c264..60c86ae6c 100644 --- a/modules/asr/CMakeLists.txt +++ b/modules/asr/CMakeLists.txt @@ -6,7 +6,7 @@ add_library(asr_sensory INTERFACE) target_sources(asr_sensory INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/device_memory.c + ${SOLUTION_VOICE_ROOT_PATH}/modules/asr/device_memory/device_memory.c ${CMAKE_CURRENT_LIST_DIR}/sensory/appAudio.c ${CMAKE_CURRENT_LIST_DIR}/sensory/sensory_asr.c ) @@ -44,7 +44,7 @@ add_library(asr_Cyberon INTERFACE) target_sources(asr_Cyberon INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/device_memory.c + ${SOLUTION_VOICE_ROOT_PATH}/modules/asr/device_memory/device_memory.c ${CMAKE_CURRENT_LIST_DIR}/Cyberon/DSpotter_asr.c ${CMAKE_CURRENT_LIST_DIR}/Cyberon/FlashReadData.c ${CMAKE_CURRENT_LIST_DIR}/Cyberon/Convert2TransferBuffer.c @@ -70,8 +70,141 @@ target_link_libraries(asr_Cyberon target_compile_definitions(asr_Cyberon INTERFACE ) + ##********************************************* ## Create aliases for sln_voice example designs ##********************************************* add_library(sln_voice::app::asr::Cyberon ALIAS asr_Cyberon) + +##***************************** +## Create Device Memory target +##***************************** + +add_library(asr_device_memory INTERFACE) + +target_sources(asr_device_memory + INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/device_memory/device_memory.c + ${CMAKE_CURRENT_LIST_DIR}/device_memory/device_memory_impl.c + +) +target_include_directories(asr_device_memory + INTERFACE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/device_memory +) +## suppress all linker warnings +target_link_options(asr_device_memory + INTERFACE + -Wl,-w +) + +target_compile_definitions(asr_device_memory + INTERFACE +) + +##********************************************* +## Create aliases for sln_voice example designs +##********************************************* + +add_library(sln_voice::app::asr::device_memory ALIAS asr_device_memory) + +##***************************** +## Create GPIO Control target +##***************************** + +add_library(asr_gpio_ctrl INTERFACE) + +target_sources(asr_gpio_ctrl + INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/gpio_ctrl/gpi_ctrl.c + ${CMAKE_CURRENT_LIST_DIR}/gpio_ctrl/leds.c +) +target_include_directories(asr_gpio_ctrl + INTERFACE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/gpio_ctrl +) +## suppress all linker warnings +target_link_options(asr_gpio_ctrl + INTERFACE + -Wl,-w +) + +target_compile_definitions(asr_gpio_ctrl + INTERFACE +) + +##********************************************* +## Create aliases for sln_voice example designs +##********************************************* + +add_library(sln_voice::app::asr::gpio_ctrl ALIAS asr_gpio_ctrl) + +##***************************** +## Create Intent Engine target +##***************************** + +add_library(asr_intent_engine INTERFACE) + +target_sources(asr_intent_engine + INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/intent_engine/intent_engine.c + ${CMAKE_CURRENT_LIST_DIR}/intent_engine/intent_engine_io.c + ${CMAKE_CURRENT_LIST_DIR}/intent_engine/intent_engine_support.c + +) +target_include_directories(asr_intent_engine + INTERFACE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/intent_engine +) +## suppress all linker warnings +target_link_options(asr_intent_engine + INTERFACE + -Wl,-w +) + +target_compile_definitions(asr_intent_engine + INTERFACE +) + +##********************************************* +## Create aliases for sln_voice example designs +##********************************************* + +add_library(sln_voice::app::asr::intent_engine ALIAS asr_intent_engine) + +##***************************** +## Create Intent Handler target +##***************************** + +add_library(asr_intent_handler INTERFACE) + +target_sources(asr_intent_handler + INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/intent_handler/intent_handler.c + ${CMAKE_CURRENT_LIST_DIR}/intent_handler/audio_response/audio_response.c +) +target_include_directories(asr_intent_handler + INTERFACE + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/intent_handler + ${CMAKE_CURRENT_LIST_DIR}/intent_handler/audio_response +) +## suppress all linker warnings +target_link_options(asr_intent_handler + INTERFACE + -Wl,-w +) + +target_compile_definitions(asr_intent_handler + INTERFACE +) + +##********************************************* +## Create aliases for sln_voice example designs +##********************************************* + +add_library(sln_voice::app::asr::intent_handler ALIAS asr_intent_handler) diff --git a/modules/asr/Cyberon/DSpotter_asr.c b/modules/asr/Cyberon/DSpotter_asr.c index f37058d64..89c0f52ab 100644 --- a/modules/asr/Cyberon/DSpotter_asr.c +++ b/modules/asr/Cyberon/DSpotter_asr.c @@ -32,14 +32,16 @@ #define VOLUME_SCALE_RECONG 800 // The AGC volume scale percentage for recognition. It depends on original microphone data. static uint8_t *g_lpbyDSpotterMem = NULL; +#ifndef UART_DUMP_RECORD static size_t g_nRecordFrameCount = 0; +#endif devmem_manager_t *devmem_ctx = NULL; //https://www.xmos.ai/documentation/XM-014363-PC-4/html/prog-guide/prog-ref/xcc-pragma-directives/pragmas.html //#pragma stackfunction n. This pragma allocates n words ( int s) of stack space for the next function declaration in the current translation unit. //pragma stackfunction 1500 => Stack size is 1500*sizeof(int) = 6000 -#pragma stackfunction 1500 +#pragma stackfunction 2500 asr_port_t asr_init(int32_t *model, int32_t *grammar, devmem_manager_t *devmem) { DSpotterInitData oDSpotterInitData; @@ -87,7 +89,7 @@ asr_port_t asr_init(int32_t *model, int32_t *grammar, devmem_manager_t *devmem) return NULL; } - DBG_TRACE("The list of trigger word: \r\n"); + DBG_TRACE("The list of trigger words: \r\n"); nCount = DSpotterHL_GetDisplayCommandCount(DSPOTTER_HL_TRIGGER_STAGE); for (int i = 0; i < nCount; i++) { @@ -98,15 +100,14 @@ asr_port_t asr_init(int32_t *model, int32_t *grammar, devmem_manager_t *devmem) nCount = DSpotterHL_GetDisplayCommandCount(DSPOTTER_HL_COMMAND_STAGE); if (nCount > 0) { - DBG_TRACE("The list of command word: \r\n"); + DBG_TRACE("The list of command words: \r\n"); for (int i = 0; i < nCount; i++) { DSpotterHL_GetDisplayCommand(DSPOTTER_HL_COMMAND_STAGE, i, szCommand, sizeof(szCommand), &nCmdID); - DBG_TRACE(" %s, ID = %d\r\n", szCommand, nCmdID); + DBG_TRACE("%d %s, ID = %d\r\n", i, szCommand, nCmdID); } } DBG_TRACE("\r\n"); - return (asr_port_t)100; } @@ -140,7 +141,6 @@ asr_error_t asr_process(asr_port_t *ctx, int16_t *audio_buf, size_t buf_len) // uint32_t timer_start = get_reference_time(); int nRet = DSpotterHL_AddSampleNoFlow(audio_buf, buf_len); - // Uncomment the two lines below to compute MIPS usage. // uint32_t timer_end = get_reference_time(); // asr_printf("DSpotter processing time: %lu (us)\n", (timer_end - timer_start) / 100); @@ -169,13 +169,19 @@ asr_error_t asr_get_result(asr_port_t *ctx, asr_result_t *result) { DBG_TRACE("\r\nGet %s, ID=%d, Score=%d, SG_Diff=%d, Energy=%d\r\n", szCommand, nCmdID, nCmdScore, nCmdSG, nCmdEnergy); result->id = nCmdID; - - result->score = nCmdScore; - result->gscore = nCmdSG; + result->sg_diff = nCmdSG; + result->energy = nCmdEnergy; // The following result fields are not implemented result->start_index = -1; result->end_index = -1; result->duration = -1; + #if appconfINTENT_UART_DEBUG_INFO_ENABLED + static char res_info[128]; + snprintf(res_info, sizeof(res_info)-1, "ID:%d,Sc:%d,SGD:%d,En:%d\r\n", nCmdID, nCmdScore, nCmdSG, nCmdEnergy); + // Enable the printout below to see the information sent over UART + // rtos_printf(res_info); + rtos_uart_tx_write(uart_tx_ctx, (uint8_t*)&res_info, strlen(res_info)); +#endif return ASR_OK; } else diff --git a/modules/asr/Cyberon/DbgTrace.c b/modules/asr/Cyberon/DbgTrace.c index 617660f2c..2c7ba8db4 100644 --- a/modules/asr/Cyberon/DbgTrace.c +++ b/modules/asr/Cyberon/DbgTrace.c @@ -13,7 +13,9 @@ void DbgTrace(const char *lpszFormat, ...) if (n >= 0 && n < 256) { rtos_printf(szTemp); +#ifdef UART_DUMP_RECORD rtos_uart_tx_write(uart_tx_ctx, (uint8_t*)szTemp, strlen(szTemp)); +#endif } va_end(args); } diff --git a/modules/asr/Cyberon/lib/libDSpotter.a b/modules/asr/Cyberon/lib/libDSpotter.a index 215155e2b..5677d8cbc 100644 Binary files a/modules/asr/Cyberon/lib/libDSpotter.a and b/modules/asr/Cyberon/lib/libDSpotter.a differ diff --git a/modules/asr/asr.h b/modules/asr/asr.h index 5dcb2bc32..4b6e496ff 100644 --- a/modules/asr/asr.h +++ b/modules/asr/asr.h @@ -1,4 +1,4 @@ -// Copyright 2023 XMOS LIMITED. +// Copyright 2023-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef XCORE_VOICE_ASR_H #define XCORE_VOICE_ASR_H @@ -8,7 +8,7 @@ #include #include -#include "device_memory.h" +#include "device_memory/device_memory.h" /** * \addtogroup asr_api asr_api @@ -18,9 +18,9 @@ */ /** - * String output function that allows the application + * String output function that allows the application * to provide an alternative implementation. - * + * * ASR ports should call asr_printf instead of printf */ __attribute__((weak)) @@ -36,7 +36,7 @@ void asr_printf(const char * format, ...) { * Typedef to the ASR port context struct. * * An ASR port can store any data needed in the context. - * The context pointer is passed to all API methods and + * The context pointer is passed to all API methods and * can be cast to any struct defined by the ASR port. */ typedef void* asr_port_t; @@ -64,11 +64,16 @@ typedef struct asr_attributes_struct typedef struct asr_result_struct { uint16_t id; ///< Keyword or command ID + + // The following fields are optional and may not be supported by all ASR ports uint16_t score; ///< The confidence score of the detection uint16_t gscore; ///< The garbage score int32_t start_index; ///< The audio sample index that corresponds to the start of the utterance int32_t end_index; ///< The audio sample index that corresponds to the end of the utterance int32_t duration; ///< THe length of the utterance in samples + uint32_t sg_diff; ///< The voice similarity of the detection + uint32_t energy; ///< The energy of the detection + void* reserved; ///< Reserved for future use } asr_result_t; @@ -77,7 +82,7 @@ typedef struct asr_result_struct */ typedef enum asr_error_enum { ASR_OK = 0, ///< Ok - ASR_ERROR, ///< General error + ASR_ERROR, ///< General error ASR_INSUFFICIENT_MEMORY, ///< Insufficient memory for given model ASR_NOT_SUPPORTED, ///< Function not supported for given model ASR_INVALID_PARAMETER, ///< Invalid Parameter @@ -92,7 +97,7 @@ typedef enum asr_error_enum { * * \param model A pointer to the model data. * \param grammar A pointer to the grammar data (Optional). - * \param devmem_ctx A pointer to the device manager (Optional). + * \param devmem_ctx A pointer to the device manager (Optional). * Save this pointer if calling any device manager API functions. * * \returns the ASR port context. @@ -104,8 +109,8 @@ asr_port_t asr_init(int32_t *model, int32_t *grammar, devmem_manager_t *devmem_c * * \param ctx A pointer to the ASR port context. * \param attributes The attributes result. - * - * \returns Success or error code. + * + * \returns Success or error code. */ asr_error_t asr_get_attributes(asr_port_t *ctx, asr_attributes_t *attributes); @@ -115,8 +120,8 @@ asr_error_t asr_get_attributes(asr_port_t *ctx, asr_attributes_t *attributes); * \param ctx A pointer to the ASR port context. * \param audio_buf A pointer to the 16-bit PCM samples. * \param buf_len The number of PCM samples. - * - * \returns Success or error code. + * + * \returns Success or error code. */ asr_error_t asr_process(asr_port_t *ctx, int16_t *audio_buf, size_t buf_len); @@ -125,30 +130,30 @@ asr_error_t asr_process(asr_port_t *ctx, int16_t *audio_buf, size_t buf_len); * * \param ctx A pointer to the ASR port context. * \param result The processed result. - * - * \returns Success or error code. + * + * \returns Success or error code. */ asr_error_t asr_get_result(asr_port_t *ctx, asr_result_t *result); /** * Reset ASR port (if necessary). - * + * * Called before the next call to asr_process. * * \param ctx A pointer to the ASR port context. - * - * \returns Success or error code. + * + * \returns Success or error code. */ asr_error_t asr_reset(asr_port_t *ctx); /** * Release ASR port (if necessary). - * + * * The ASR port must deallocate any memory. * * \param ctx A pointer to the ASR port context. - * - * \returns Success or error code. + * + * \returns Success or error code. */ asr_error_t asr_release(asr_port_t *ctx); diff --git a/modules/asr/device_memory.c b/modules/asr/device_memory/device_memory.c similarity index 96% rename from modules/asr/device_memory.c rename to modules/asr/device_memory/device_memory.c index 0e42d45e8..d0958b15f 100644 --- a/modules/asr/device_memory.c +++ b/modules/asr/device_memory/device_memory.c @@ -1,4 +1,4 @@ -// Copyright 2023 XMOS LIMITED. +// Copyright 2023-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include #include diff --git a/modules/asr/device_memory.h b/modules/asr/device_memory/device_memory.h similarity index 99% rename from modules/asr/device_memory.h rename to modules/asr/device_memory/device_memory.h index 96b520a32..04c53fa56 100644 --- a/modules/asr/device_memory.h +++ b/modules/asr/device_memory/device_memory.h @@ -1,4 +1,4 @@ -// Copyright 2023 XMOS LIMITED. +// Copyright 2023-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef XCORE_DEVICE_MEMORY_H #define XCORE_DEVICE_MEMORY_H diff --git a/examples/ffd/src/device_memory_impl.c b/modules/asr/device_memory/device_memory_impl.c similarity index 98% rename from examples/ffd/src/device_memory_impl.c rename to modules/asr/device_memory/device_memory_impl.c index 11976438b..ff35c630a 100644 --- a/examples/ffd/src/device_memory_impl.c +++ b/modules/asr/device_memory/device_memory_impl.c @@ -1,4 +1,4 @@ -// Copyright 2023 XMOS LIMITED. +// Copyright 2023-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include #include diff --git a/test/asr/src/device_memory_impl.h b/modules/asr/device_memory/device_memory_impl.h similarity index 86% rename from test/asr/src/device_memory_impl.h rename to modules/asr/device_memory/device_memory_impl.h index 0822a303c..ea8735cbf 100644 --- a/test/asr/src/device_memory_impl.h +++ b/modules/asr/device_memory/device_memory_impl.h @@ -1,4 +1,4 @@ -// Copyright 2023 XMOS LIMITED. +// Copyright 2023-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef DEVICE_MEMORY_IMPL_H #define DEVICE_MEMORY_IMPL_H diff --git a/examples/ffd/src/gpio_ctrl/gpi_ctrl.c b/modules/asr/gpio_ctrl/gpi_ctrl.c similarity index 97% rename from examples/ffd/src/gpio_ctrl/gpi_ctrl.c rename to modules/asr/gpio_ctrl/gpi_ctrl.c index 0cfcc43d5..847fcaa81 100644 --- a/examples/ffd/src/gpio_ctrl/gpi_ctrl.c +++ b/modules/asr/gpio_ctrl/gpi_ctrl.c @@ -1,4 +1,4 @@ -// Copyright 2021-2022 XMOS LIMITED. +// Copyright 2021-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include @@ -7,7 +7,7 @@ #include "FreeRTOS.h" #include "platform/app_pll_ctrl.h" -#include "gpio_ctrl/gpi_ctrl.h" +#include "gpi_ctrl.h" __attribute__((weak)) void gpio_gpi_toggled_cb(uint32_t gpio_val) diff --git a/examples/ffd/src/gpio_ctrl/gpi_ctrl.h b/modules/asr/gpio_ctrl/gpi_ctrl.h similarity index 95% rename from examples/ffd/src/gpio_ctrl/gpi_ctrl.h rename to modules/asr/gpio_ctrl/gpi_ctrl.h index c278588fe..7165edc54 100644 --- a/examples/ffd/src/gpio_ctrl/gpi_ctrl.h +++ b/modules/asr/gpio_ctrl/gpi_ctrl.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef GPI_CTRL_H_ diff --git a/examples/ffd/src/gpio_ctrl/leds.c b/modules/asr/gpio_ctrl/leds.c similarity index 99% rename from examples/ffd/src/gpio_ctrl/leds.c rename to modules/asr/gpio_ctrl/leds.c index 3e329c60e..66e2b9e28 100644 --- a/examples/ffd/src/gpio_ctrl/leds.c +++ b/modules/asr/gpio_ctrl/leds.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -12,7 +12,7 @@ /* App headers */ #include "app_conf.h" -#include "gpio_ctrl/leds.h" +#include "leds.h" #include "platform/driver_instances.h" diff --git a/examples/ffd/src/gpio_ctrl/leds.h b/modules/asr/gpio_ctrl/leds.h similarity index 96% rename from examples/ffd/src/gpio_ctrl/leds.h rename to modules/asr/gpio_ctrl/leds.h index 97685ca96..9f739b646 100644 --- a/examples/ffd/src/gpio_ctrl/leds.h +++ b/modules/asr/gpio_ctrl/leds.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef LEDS_H_ diff --git a/examples/ffd/src/intent_engine/intent_engine.c b/modules/asr/intent_engine/intent_engine.c similarity index 96% rename from examples/ffd/src/intent_engine/intent_engine.c rename to modules/asr/intent_engine/intent_engine.c index 33f0c421a..e8d231c63 100644 --- a/examples/ffd/src/intent_engine/intent_engine.c +++ b/modules/asr/intent_engine/intent_engine.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -14,11 +14,11 @@ /* App headers */ #include "app_conf.h" #include "platform/driver_instances.h" -#include "intent_engine/intent_engine.h" -#include "intent_handler/intent_handler.h" +#include "intent_engine.h" +#include "intent_handler.h" #include "asr.h" #include "device_memory_impl.h" -#include "gpio_ctrl/leds.h" +#include "leds.h" #if ON_TILE(ASR_TILE_NO) @@ -112,6 +112,7 @@ static void timeout_event_handler(TimerHandle_t pxTimer) intent_state = STATE_EXPECTING_WAKEWORD; } } +asr_result_t last_asr_result = {0}; #pragma stackfunction 1000 void intent_engine_task(void *args) @@ -162,7 +163,6 @@ void intent_engine_task(void *args) if (intent_handler_response_playing()) continue; asr_error = asr_process(asr_ctx, buf_short, SAMPLES_PER_ASR); - if (asr_error == ASR_EVALUATION_EXPIRED) { led_indicate_end_of_eval(); continue; @@ -170,6 +170,8 @@ void intent_engine_task(void *args) if (asr_error != ASR_OK) continue; asr_error = asr_get_result(asr_ctx, &asr_result); + memcpy(&last_asr_result, &asr_result, sizeof(asr_result_t)); + if (asr_error != ASR_OK) continue; word_id = asr_result.id; @@ -211,7 +213,7 @@ void intent_engine_task(void *args) void intent_engine_ready_sync(void) { int sync = 0; -#if ON_TILE(AUDIO_PIPELINE_TILE_NO) +#if ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) size_t len = rtos_intertile_rx_len(intertile_ctx, appconfINTENT_ENGINE_READY_SYNC_PORT, RTOS_OSAL_WAIT_FOREVER); xassert(len == sizeof(sync)); rtos_intertile_rx_data(intertile_ctx, &sync, sizeof(sync)); diff --git a/examples/ffd/src/intent_engine/intent_engine.h b/modules/asr/intent_engine/intent_engine.h similarity index 96% rename from examples/ffd/src/intent_engine/intent_engine.h rename to modules/asr/intent_engine/intent_engine.h index 1cf46d397..81b030445 100644 --- a/examples/ffd/src/intent_engine/intent_engine.h +++ b/modules/asr/intent_engine/intent_engine.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef INTENT_ENGINE_H_ diff --git a/examples/ffd/src/intent_engine/intent_engine_io.c b/modules/asr/intent_engine/intent_engine_io.c similarity index 86% rename from examples/ffd/src/intent_engine/intent_engine_io.c rename to modules/asr/intent_engine/intent_engine_io.c index 9077af513..2c73d916e 100644 --- a/examples/ffd/src/intent_engine/intent_engine_io.c +++ b/modules/asr/intent_engine/intent_engine_io.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -96,6 +96,13 @@ void intent_engine_process_asr_result(int word_id) } } rtos_printf("RECOGNIZED: 0x%x, %s\n", (int) word_id, (char*)text); +#if appconfINTENT_UART_DEBUG_INFO_ENABLED + static char res_info[128]; + snprintf(res_info, sizeof(res_info)-1, "Cmd:%s\r\n", text); + // Enable the printout below to see the information sent over UART + // rtos_printf(res_info); + rtos_uart_tx_write(uart_tx_ctx, (uint8_t*)&res_info, strlen(res_info)); +#endif intent_engine_play_response(wav_id); } @@ -104,7 +111,7 @@ int32_t intent_engine_create(uint32_t priority, void *args) { q_intent = (QueueHandle_t) args; -#if ASR_TILE_NO == AUDIO_PIPELINE_TILE_NO +#if ASR_TILE_NO == AUDIO_PIPELINE_OUTPUT_TILE_NO intent_engine_task_create(priority); #else intent_engine_intertile_task_create(priority); @@ -115,8 +122,8 @@ int32_t intent_engine_create(uint32_t priority, void *args) int32_t intent_engine_sample_push(int32_t *buf, size_t frames) { -#if appconfINTENT_ENABLED && ON_TILE(AUDIO_PIPELINE_TILE_NO) -#if ASR_TILE_NO == AUDIO_PIPELINE_TILE_NO +#if appconfINTENT_ENABLED && ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) +#if ASR_TILE_NO == AUDIO_PIPELINE_OUTPUT_TILE_NO intent_engine_samples_send_local( frames, buf); diff --git a/examples/ffd/src/intent_engine/intent_engine_support.c b/modules/asr/intent_engine/intent_engine_support.c similarity index 90% rename from examples/ffd/src/intent_engine/intent_engine_support.c rename to modules/asr/intent_engine/intent_engine_support.c index c393b8819..b8c319a7f 100644 --- a/examples/ffd/src/intent_engine/intent_engine_support.c +++ b/modules/asr/intent_engine/intent_engine_support.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -14,7 +14,7 @@ /* App headers */ #include "app_conf.h" #include "platform/driver_instances.h" -#include "intent_engine/intent_engine.h" +#include "intent_engine.h" #if ON_TILE(ASR_TILE_NO) @@ -29,8 +29,8 @@ void intent_engine_stream_buf_reset(void) #endif /* ON_TILE(ASR_TILE_NO) */ -#if ASR_TILE_NO != AUDIO_PIPELINE_TILE_NO -#if ON_TILE(AUDIO_PIPELINE_TILE_NO) +#if ASR_TILE_NO != AUDIO_PIPELINE_OUTPUT_TILE_NO +#if ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) void intent_engine_samples_send_remote( rtos_intertile_t *intertile, @@ -45,7 +45,7 @@ void intent_engine_samples_send_remote( sizeof(int32_t) * frame_count); } -#else /* ON_TILE(AUDIO_PIPELINE_TILE_NO) */ +#else /* ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) */ static void intent_engine_intertile_samples_in_task(void *arg) { @@ -93,10 +93,10 @@ void intent_engine_intertile_task_create(uint32_t priority) NULL); } -#endif /* ON_TILE(AUDIO_PIPELINE_TILE_NO) */ -#endif /* ASR_TILE_NO != AUDIO_PIPELINE_TILE_NO */ +#endif /* ON_TILE(AUDIO_PIPELINE_OUTPUT_TILE_NO) */ +#endif /* ASR_TILE_NO != AUDIO_PIPELINE_OUTPUT_TILE_NO */ -#if ASR_TILE_NO == AUDIO_PIPELINE_TILE_NO +#if ASR_TILE_NO == AUDIO_PIPELINE_OUTPUT_TILE_NO #if ON_TILE(ASR_TILE_NO) void intent_engine_samples_send_local( @@ -110,6 +110,7 @@ void intent_engine_samples_send_local( if (xStreamBufferSend(samples_to_engine_stream_buf, processed_audio_frame, bytes_to_send, 0) != bytes_to_send) { rtos_printf("lost local output samples for intent\n"); } + } else { rtos_printf("intent engine streambuffer not ready\n"); } @@ -130,4 +131,4 @@ void intent_engine_task_create(unsigned priority) } #endif /* ON_TILE(ASR_TILE_NO) */ -#endif /* ASR_TILE_NO == AUDIO_PIPELINE_TILE_NO */ +#endif /* ASR_TILE_NO == AUDIO_PIPELINE_OUTPUT_TILE_NO */ diff --git a/examples/ffd/src/intent_handler/audio_response/audio_response.c b/modules/asr/intent_handler/audio_response/audio_response.c similarity index 77% rename from examples/ffd/src/intent_handler/audio_response/audio_response.c rename to modules/asr/intent_handler/audio_response/audio_response.c index f28024fe5..79c1c2c01 100644 --- a/examples/ffd/src/intent_handler/audio_response/audio_response.c +++ b/modules/asr/intent_handler/audio_response/audio_response.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -13,7 +13,7 @@ /* App headers */ #include "app_conf.h" #include "platform/driver_instances.h" -#include "intent_handler/intent_handler.h" +#include "intent_handler.h" #include "audio_response.h" #include "fs_support.h" #include "ff.h" @@ -42,8 +42,8 @@ static const char *audio_files_en[] = { #define NUM_FILES (sizeof(audio_files_en) / sizeof(char *)) -static int16_t file_audio[appconfAUDIO_PIPELINE_FRAME_ADVANCE * sizeof(int16_t)]; -static int32_t i2s_audio[2*(appconfAUDIO_PIPELINE_FRAME_ADVANCE * sizeof(int32_t))]; +static int16_t file_audio[appconfAUDIO_PIPELINE_FRAME_ADVANCE]; +static int32_t i2s_audio[2*(appconfAUDIO_PIPELINE_FRAME_ADVANCE)]; static drwav *wav_files = NULL; #pragma stackfunction 3000 @@ -95,12 +95,22 @@ void audio_response_play(int32_t id) { i2s_audio[(2*i)+0] = (int32_t) file_audio[i] << 16; i2s_audio[(2*i)+1] = (int32_t) file_audio[i] << 16; } - - rtos_i2s_tx(i2s_ctx, - (int32_t*) i2s_audio, - appconfAUDIO_PIPELINE_FRAME_ADVANCE, - portMAX_DELAY); - + if (appconfI2S_MODE == appconfI2S_MODE_MASTER) + { + rtos_i2s_tx(i2s_ctx, + (int32_t*) i2s_audio, + appconfAUDIO_PIPELINE_FRAME_ADVANCE, + portMAX_DELAY); + } else if (appconfI2S_MODE == appconfI2S_MODE_SLAVE) + { + rtos_intertile_tx(intertile_ctx, + appconfI2S_OUTPUT_SLAVE_PORT, + i2s_audio, + sizeof(i2s_audio)); + } else { + // Invalid I2S mode + xassert(0); + } if (framesRead != appconfAUDIO_PIPELINE_FRAME_ADVANCE) { drwav_seek_to_pcm_frame(&tmp, 0); break; diff --git a/examples/ffd/src/intent_handler/audio_response/audio_response.h b/modules/asr/intent_handler/audio_response/audio_response.h similarity index 87% rename from examples/ffd/src/intent_handler/audio_response/audio_response.h rename to modules/asr/intent_handler/audio_response/audio_response.h index 233bf0a99..97ed1e82e 100644 --- a/examples/ffd/src/intent_handler/audio_response/audio_response.h +++ b/modules/asr/intent_handler/audio_response/audio_response.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef AUDIO_RESPONSE_H_ diff --git a/examples/ffd/src/intent_handler/audio_response/dr_wav.h b/modules/asr/intent_handler/audio_response/dr_wav.h similarity index 99% rename from examples/ffd/src/intent_handler/audio_response/dr_wav.h rename to modules/asr/intent_handler/audio_response/dr_wav.h index 94edf4ae7..d8da0c092 100644 --- a/examples/ffd/src/intent_handler/audio_response/dr_wav.h +++ b/modules/asr/intent_handler/audio_response/dr_wav.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. diff --git a/examples/ffd/src/intent_handler/audio_response/dr_wav_freertos_port.h b/modules/asr/intent_handler/audio_response/dr_wav_freertos_port.h similarity index 98% rename from examples/ffd/src/intent_handler/audio_response/dr_wav_freertos_port.h rename to modules/asr/intent_handler/audio_response/dr_wav_freertos_port.h index e530ab7c8..26c51e72e 100644 --- a/examples/ffd/src/intent_handler/audio_response/dr_wav_freertos_port.h +++ b/modules/asr/intent_handler/audio_response/dr_wav_freertos_port.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef DR_WAV_FREERTOS_PORT_H_ diff --git a/examples/ffd/src/intent_handler/intent_handler.c b/modules/asr/intent_handler/intent_handler.c similarity index 91% rename from examples/ffd/src/intent_handler/intent_handler.c rename to modules/asr/intent_handler/intent_handler.c index 8d052c9c8..0d26de9da 100644 --- a/examples/ffd/src/intent_handler/intent_handler.c +++ b/modules/asr/intent_handler/intent_handler.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -14,11 +14,11 @@ /* App headers */ #include "app_conf.h" #include "platform/driver_instances.h" -#include "intent_handler/intent_handler.h" +#include "intent_handler.h" #include "fs_support.h" #include "ff.h" #include "audio_response.h" -#include "intent_engine/intent_engine.h" +#include "intent_engine.h" #define WAKEUP_LOW (appconfINTENT_WAKEUP_EDGE_TYPE) #define WAKEUP_HIGH (appconfINTENT_WAKEUP_EDGE_TYPE == 0) @@ -56,14 +56,14 @@ static void proc_keyword_res(void *args) { vTaskDelay(pdMS_TO_TICKS(appconfINTENT_TRANSPORT_DELAY_MS)); rtos_gpio_port_out(gpio_ctx_t0, p_out_wakeup, WAKEUP_LOW); } -#if appconfINTENT_I2C_OUTPUT_ENABLED +#if appconfINTENT_I2C_MASTER_OUTPUT_ENABLED i2c_res_t ret; uint32_t buf = id; size_t sent = 0; ret = rtos_i2c_master_write( i2c_master_ctx, - appconfINTENT_I2C_OUTPUT_DEVICE_ADDR, + appconfINTENT_I2C_MASTER_DEVICE_ADDR, (uint8_t*)&buf, sizeof(uint32_t), &sent, @@ -79,7 +79,7 @@ static void proc_keyword_res(void *args) { rtos_uart_tx_write(uart_tx_ctx, (uint8_t*)&buf_uart, sizeof(uint32_t)); #endif #if appconfAUDIO_PLAYBACK_ENABLED - audio_response_playing = true; + audio_response_playing = true; audio_response_play(id); audio_response_playing = false; #endif @@ -98,7 +98,6 @@ int32_t intent_handler_create(uint32_t priority, void *args) args, priority, NULL); - return 0; } diff --git a/examples/ffd/src/intent_handler/intent_handler.h b/modules/asr/intent_handler/intent_handler.h similarity index 94% rename from examples/ffd/src/intent_handler/intent_handler.h rename to modules/asr/intent_handler/intent_handler.h index 4d3d8b781..5fd3f2107 100644 --- a/examples/ffd/src/intent_handler/intent_handler.h +++ b/modules/asr/intent_handler/intent_handler.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef INTENT_HANDLER_H_ diff --git a/modules/asr/sensory/sensory_asr.c b/modules/asr/sensory/sensory_asr.c index 98cad2ce0..a05c51d12 100644 --- a/modules/asr/sensory/sensory_asr.c +++ b/modules/asr/sensory/sensory_asr.c @@ -200,6 +200,13 @@ asr_error_t asr_get_result(asr_port_t *ctx, asr_result_t *result) result->start_index = sensory_asr->start_index; result->end_index = sensory_asr->end_index; result->duration = sensory_asr->duration; +#if appconfINTENT_UART_DEBUG_INFO_ENABLED + static char res_info[128]; + snprintf(res_info, sizeof(res_info)-1, "score:%d,start:%d,end:%d,dur:%d\r\n", result->score, result->start_index, result->end_index, result->duration); + // Enable the printout below to see the information sent over UART + // rtos_printf(res_info); + rtos_uart_tx_write(uart_tx_ctx, (uint8_t*)&res_info, strlen(res_info)); +#endif } else { result->id = 0; result->score = 0; diff --git a/modules/audio_pipelines/reference/CMakeLists.txt b/modules/audio_pipelines/reference/CMakeLists.txt index b2b11e87c..159317bfb 100644 --- a/modules/audio_pipelines/reference/CMakeLists.txt +++ b/modules/audio_pipelines/reference/CMakeLists.txt @@ -1,5 +1,5 @@ ##****************************************** -## Create fixed_delay AEC+IC+NS+AGC +## Create fixed_delay AEC+IC+NS+AGC ## 2 mic input channels # 2 reference input channels ##****************************************** @@ -30,7 +30,7 @@ target_link_libraries(fixed_delay_aec_ic_ns_agc_2mic_2ref ) ##****************************************** -## Create ADEC "prevarch" AEC+IC+NS+AGC +## Create ADEC "prevarch" AEC+IC+NS+AGC ## 2 mic input channels # 2 reference input channels ##****************************************** @@ -66,7 +66,7 @@ target_link_libraries(adec_aec_ic_ns_agc_2mic_2ref ) ##****************************************** -## Create ADEC altarch AEC+IC+NS+AGC +## Create ADEC altarch AEC+IC+NS+AGC ## 2 mic input channels # 2 reference input channels ##****************************************** @@ -108,7 +108,8 @@ target_link_libraries(adec_altarch_aec_ic_ns_agc_2mic_2ref add_library(empty_2mic_2ref INTERFACE) target_sources(empty_2mic_2ref INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/empty/audio_pipeline.c + ${CMAKE_CURRENT_LIST_DIR}/empty/audio_pipeline_t0.c + ${CMAKE_CURRENT_LIST_DIR}/empty/audio_pipeline_t1.c ) target_include_directories(empty_2mic_2ref INTERFACE diff --git a/modules/audio_pipelines/reference/empty/audio_pipeline_dsp.h b/modules/audio_pipelines/reference/empty/audio_pipeline_dsp.h new file mode 100644 index 000000000..3d5f0822b --- /dev/null +++ b/modules/audio_pipelines/reference/empty/audio_pipeline_dsp.h @@ -0,0 +1,20 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef AUDIO_PIPELINE_DSP_H_ +#define AUDIO_PIPELINE_DSP_H_ + +#include +#include "app_conf.h" + + +/* Note: Changing the order here will effect the channel order for + * audio_pipeline_input() and audio_pipeline_output() + */ +typedef struct { + int32_t samples[appconfAUDIO_PIPELINE_CHANNELS][appconfAUDIO_PIPELINE_FRAME_ADVANCE]; + int32_t aec_reference_audio_samples[appconfAUDIO_PIPELINE_CHANNELS][appconfAUDIO_PIPELINE_FRAME_ADVANCE]; + int32_t mic_samples_passthrough[appconfAUDIO_PIPELINE_CHANNELS][appconfAUDIO_PIPELINE_FRAME_ADVANCE]; +} frame_data_t; + +#endif /* AUDIO_PIPELINE_DSP_H_ */ diff --git a/modules/audio_pipelines/reference/empty/audio_pipeline.c b/modules/audio_pipelines/reference/empty/audio_pipeline_t0.c similarity index 86% rename from modules/audio_pipelines/reference/empty/audio_pipeline.c rename to modules/audio_pipelines/reference/empty/audio_pipeline_t0.c index 03f5039a3..fbe44f457 100644 --- a/modules/audio_pipelines/reference/empty/audio_pipeline.c +++ b/modules/audio_pipelines/reference/empty/audio_pipeline_t0.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -19,16 +19,13 @@ /* App headers */ #include "app_conf.h" #include "audio_pipeline.h" +#include "audio_pipeline_dsp.h" #if appconfAUDIO_PIPELINE_FRAME_ADVANCE != 240 #error This pipeline is only configured for 240 frame advance #endif -typedef struct { - int32_t samples[appconfAUDIO_PIPELINE_CHANNELS][appconfAUDIO_PIPELINE_FRAME_ADVANCE]; - int32_t aec_reference_audio_samples[appconfAUDIO_PIPELINE_CHANNELS][appconfAUDIO_PIPELINE_FRAME_ADVANCE]; - int32_t mic_samples_passthrough[appconfAUDIO_PIPELINE_CHANNELS][appconfAUDIO_PIPELINE_FRAME_ADVANCE]; -} frame_data_t; +#if ON_TILE(0) static void *audio_pipeline_input_i(void *input_app_data) { @@ -99,3 +96,5 @@ void audio_pipeline_init( appconfAUDIO_PIPELINE_TASK_PRIORITY, stage_count); } + +#endif /* ON_TILE(0)*/ diff --git a/modules/audio_pipelines/reference/empty/audio_pipeline_t1.c b/modules/audio_pipelines/reference/empty/audio_pipeline_t1.c new file mode 100644 index 000000000..ddf31c8df --- /dev/null +++ b/modules/audio_pipelines/reference/empty/audio_pipeline_t1.c @@ -0,0 +1,95 @@ +// Copyright 2024 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* STD headers */ +#include +#include +#include + +/* FreeRTOS headers */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "queue.h" +#include "stream_buffer.h" + +/* Library headers */ +#include "generic_pipeline.h" + +/* App headers */ +#include "app_conf.h" +#include "audio_pipeline.h" +#include "audio_pipeline_dsp.h" + +#if appconfAUDIO_PIPELINE_FRAME_ADVANCE != 240 +#error This pipeline is only configured for 240 frame advance +#endif + +#if ON_TILE(1) + +static void *audio_pipeline_input_i(void *input_app_data) +{ + frame_data_t *frame_data; + frame_data = pvPortMalloc(sizeof(frame_data_t)); + memset(frame_data, 0x00, sizeof(frame_data_t)); + + audio_pipeline_input(input_app_data, + (int32_t **)frame_data->aec_reference_audio_samples, + 4, + appconfAUDIO_PIPELINE_FRAME_ADVANCE); + + memcpy(frame_data->samples, frame_data->mic_samples_passthrough, sizeof(frame_data->samples)); + + return frame_data; +} + +static int audio_pipeline_output_i(frame_data_t *frame_data, + void *output_app_data) +{ + + rtos_intertile_tx(intertile_ctx, + appconfAUDIOPIPELINE_PORT, + frame_data, + sizeof(frame_data_t)); + + return AUDIO_PIPELINE_FREE_FRAME; +} + +void empty_stage(void) +{ + ; +} + +static void initialize_pipeline_stages(void) +{ + ; +} + +void audio_pipeline_init( + void *input_app_data, + void *output_app_data) +{ + const int stage_count = 2; + const pipeline_stage_t stages[] = { + (pipeline_stage_t)empty_stage, + (pipeline_stage_t)empty_stage, + }; + + const configSTACK_DEPTH_TYPE stage_stack_sizes[] = { + configMINIMAL_STACK_SIZE + RTOS_THREAD_STACK_SIZE(empty_stage) + RTOS_THREAD_STACK_SIZE(audio_pipeline_input_i), + configMINIMAL_STACK_SIZE + RTOS_THREAD_STACK_SIZE(empty_stage) + RTOS_THREAD_STACK_SIZE(audio_pipeline_output_i), + }; + + initialize_pipeline_stages(); + + generic_pipeline_init((pipeline_input_t)audio_pipeline_input_i, + (pipeline_output_t)audio_pipeline_output_i, + input_app_data, + output_app_data, + stages, + (const size_t*) stage_stack_sizes, + appconfAUDIO_PIPELINE_TASK_PRIORITY, + stage_count); + +} +#endif /* ON_TILE(1)*/ diff --git a/modules/audio_pipelines/reference/fixed_delay/audio_pipeline_t0.c b/modules/audio_pipelines/reference/fixed_delay/audio_pipeline_t0.c index 434b426cb..60d01f6f8 100644 --- a/modules/audio_pipelines/reference/fixed_delay/audio_pipeline_t0.c +++ b/modules/audio_pipelines/reference/fixed_delay/audio_pipeline_t0.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -65,6 +65,7 @@ static void *audio_pipeline_input_i(void *input_app_data) static int audio_pipeline_output_i(frame_data_t *frame_data, void *output_app_data) { + return audio_pipeline_output(output_app_data, (int32_t **)frame_data->samples, 6, @@ -144,7 +145,6 @@ void audio_pipeline_init( void *output_app_data) { const int stage_count = 3; - const pipeline_stage_t stages[] = { (pipeline_stage_t)stage_vnr_and_ic, (pipeline_stage_t)stage_ns, @@ -159,6 +159,7 @@ void audio_pipeline_init( initialize_pipeline_stages(); + generic_pipeline_init((pipeline_input_t)audio_pipeline_input_i, (pipeline_output_t)audio_pipeline_output_i, input_app_data, @@ -167,6 +168,7 @@ void audio_pipeline_init( (const size_t*) stage_stack_sizes, appconfAUDIO_PIPELINE_TASK_PRIORITY, stage_count); + } #endif /* ON_TILE(0)*/ diff --git a/modules/audio_pipelines/reference/fixed_delay/audio_pipeline_t1.c b/modules/audio_pipelines/reference/fixed_delay/audio_pipeline_t1.c index 2bb96defb..670168dde 100644 --- a/modules/audio_pipelines/reference/fixed_delay/audio_pipeline_t1.c +++ b/modules/audio_pipelines/reference/fixed_delay/audio_pipeline_t1.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. /* STD headers */ @@ -35,7 +35,6 @@ static aec_ctx_t DWORD_ALIGNED aec_state = {}; static void *audio_pipeline_input_i(void *input_app_data) { frame_data_t *frame_data; - frame_data = pvPortMalloc(sizeof(frame_data_t)); memset(frame_data, 0x00, sizeof(frame_data_t)); @@ -54,10 +53,12 @@ static void *audio_pipeline_input_i(void *input_app_data) static int audio_pipeline_output_i(frame_data_t *frame_data, void *output_app_data) { + rtos_intertile_tx(intertile_ctx, appconfAUDIOPIPELINE_PORT, frame_data, sizeof(frame_data_t)); + return AUDIO_PIPELINE_FREE_FRAME; } @@ -152,7 +153,6 @@ void audio_pipeline_init( void *output_app_data) { const int stage_count = 2; - const pipeline_stage_t stages[] = { (pipeline_stage_t)stage_delay, (pipeline_stage_t)stage_aec, @@ -173,5 +173,6 @@ void audio_pipeline_init( (const size_t*) stage_stack_sizes, appconfAUDIO_PIPELINE_TASK_PRIORITY, stage_count); + } #endif /* ON_TILE(1) */ diff --git a/modules/audio_pipelines/referenceless/audio_pipeline.c b/modules/audio_pipelines/referenceless/audio_pipeline.c index 8f90ca23f..1c95b6538 100644 --- a/modules/audio_pipelines/referenceless/audio_pipeline.c +++ b/modules/audio_pipelines/referenceless/audio_pipeline.c @@ -60,10 +60,16 @@ typedef struct agc_stage_ctx { agc_state_t state; } agc_stage_ctx_t; +#if !appconfAUDIO_PIPELINE_SKIP_IC_AND_VNR static ic_stage_ctx_t DWORD_ALIGNED ic_stage_state = {}; static vnr_pred_stage_ctx_t DWORD_ALIGNED vnr_pred_stage_state = {}; +#endif +#if !appconfAUDIO_PIPELINE_SKIP_NS static ns_stage_ctx_t DWORD_ALIGNED ns_stage_state = {}; +#endif +#if !appconfAUDIO_PIPELINE_SKIP_AGC static agc_stage_ctx_t DWORD_ALIGNED agc_stage_state = {}; +#endif static trace_data_t* trace_data = 0; @@ -162,19 +168,23 @@ static void stage_agc(frame_data_t *frame_data) } static void initialize_pipeline_stages(void) { +#if !appconfAUDIO_PIPELINE_SKIP_IC_AND_VNR ic_init(&ic_stage_state.state); // Set some VNR parameters - ic_stage_state.state.ic_adaption_controller_state.adaption_controller_config.input_vnr_threshold = + ic_stage_state.state.ic_adaption_controller_state.adaption_controller_config.input_vnr_threshold = f64_to_float_s32(IC_INPUT_VNR_THRESHOLD); - ic_stage_state.state.ic_adaption_controller_state.adaption_controller_config.input_vnr_threshold_high = + ic_stage_state.state.ic_adaption_controller_state.adaption_controller_config.input_vnr_threshold_high = f64_to_float_s32(IC_INPUT_VNR_THRESHOLD_HIGH); - +#endif +#if !appconfAUDIO_PIPELINE_SKIP_NS ns_init(&ns_stage_state.state); - +#endif +#if !appconfAUDIO_PIPELINE_SKIP_AGC agc_init(&agc_stage_state.state, &AGC_PROFILE_ASR); agc_stage_state.md.aec_ref_power = AGC_META_DATA_NO_AEC; agc_stage_state.md.aec_corr_factor = AGC_META_DATA_NO_AEC; +#endif } void audio_pipeline_init( diff --git a/modules/core b/modules/core index c4582cb3c..ebe8ee434 160000 --- a/modules/core +++ b/modules/core @@ -1 +1 @@ -Subproject commit c4582cb3ce4da34c8757a6f8f7df8935496038eb +Subproject commit ebe8ee43467132dee919eb754b5bb9d93558906f diff --git a/modules/inferencing/CMakeLists.txt b/modules/inferencing/CMakeLists.txt deleted file mode 100644 index a6db7b1ad..000000000 --- a/modules/inferencing/CMakeLists.txt +++ /dev/null @@ -1,159 +0,0 @@ -## ******************** -## Create lib_nn target -## ******************** - -add_library(inferencing_lib_nn STATIC) - - ## Source files -file(GLOB_RECURSE NN_SOURCES "lib_nn/lib_nn/src/c/*.c") - -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/AggregateFn.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/AggregateFn_DW.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/Filter2D.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/MemCpyFn.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/OutputTransformFn.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/filt2d/conv2d_utils.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/filt2d/util.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/filt2d/geom/Filter2dGeometry.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/filt2d/geom/ImageGeometry.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/filt2d/geom/WindowGeometry.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/cpp/filt2d/geom/WindowLocation.cpp") -list(APPEND NN_SOURCES "lib_nn/lib_nn/src/asm/asm_constants.c") - -if(${CMAKE_SYSTEM_NAME} STREQUAL XCORE_XS3A) - - file(GLOB_RECURSE NN_SOURCES_ASM lib_nn/lib_nn/src/asm/*.S) - - ## cmake doesn't recognize .S files as assembly by default - set_source_files_properties(LIB_NN_SOURCES_ASM PROPERTIES LANGUAGE ASM) - - ## Assume all asm is XS3A for now - set(XCORE_XS3A_SOURCES ${NN_SOURCES_ASM}) - - target_compile_options(inferencing_lib_nn - PRIVATE - "-Os" - "-Wno-xcore-fptrgroup" - "-Wp,-w" - $<$:-std=c++11> - ) -else() - set(CMAKE_CXX_FLAGS "-std=c++11" CACHE STRING "C++ Compiler Base Flags" FORCE) - target_compile_definitions(inferencing_lib_nn - PRIVATE - NN_USE_REF - ) - - target_compile_options(inferencing_lib_nn - PRIVATE - $<$:-std=c++11> - ) -endif() - -target_sources(inferencing_lib_nn - PRIVATE - ${NN_SOURCES} - ${NN_SOURCES_ASM} -) -target_include_directories(inferencing_lib_nn - PUBLIC - lib_nn/lib_nn/api - lib_nn/lib_nn/.. -) - -## ********************************** -## Patch lib_tflite_micro -## ********************************** - -find_package(Git) -if(NOT Git_FOUND) - message(FATAL_ERROR "Git not found. Please install git and retry.") -endif() - -set(PATCHED_FLAG_FILE ${CMAKE_CURRENT_LIST_DIR}/lib_tflite_micro/patched.flag) - -add_custom_command( - OUTPUT ${PATCHED_FLAG_FILE} - COMMAND git submodule update -f lib_tflite_micro/submodules/tflite-micro - COMMAND git apply --directory lib_tflite_micro/submodules/tflite-micro/tensorflow patches/tflite-micro.patch - COMMAND ${CMAKE_COMMAND} -E touch ${PATCHED_FLAG_FILE} - COMMENT - "Resetting and applying patch to lib_tflite_micro" - WORKING_DIRECTORY - ${CMAKE_CURRENT_LIST_DIR}/lib_tflite_micro - VERBATIM -) - -add_custom_target(lib_tflite_micro_patch DEPENDS ${PATCHED_FLAG_FILE}) - -## ****************************** -## Create lib_tflite_micro target -## ****************************** - -SET(TOP_DIR ${CMAKE_CURRENT_LIST_DIR}/lib_tflite_micro) -include(${TOP_DIR}/cmakefiles/xtflm.cmake) - -add_library(inferencing_tflite_micro STATIC) - -if(${CMAKE_SYSTEM_NAME} STREQUAL XCORE_XS3A) - ## Source files - file(GLOB_RECURSE TFLIB_SOURCES_ASM ${TOP_DIR}/lib_tflite_micro/src/*.S) - set_source_files_properties(TFLIB_SOURCES_ASM PROPERTIES LANGUAGE ASM) - - target_compile_options(inferencing_tflite_micro - PRIVATE - "-Os" - "-Wno-xcore-fptrgroup" - $<$:-std=c++11> - "-Wp,-w" - ) -else() - target_compile_definitions(inferencing_tflite_micro - PRIVATE - __xtflm_conf_h_exists__ - ) -endif() - -target_compile_definitions(inferencing_tflite_micro - PUBLIC - NO_INTERPRETER - TF_LITE_STATIC_MEMORY - TF_LITE_STRIP_ERROR_STRINGS - XTFLM_DISABLED -) - -target_sources(inferencing_tflite_micro - PRIVATE - ${TFLIB_SOURCES_ASM} - ${TFLITE_SOURCES} - ${TFLM_KERNEL_SOURCES} - ${XTFLIB_KERNEL_SOURCES} -) - -target_include_directories(inferencing_tflite_micro - PUBLIC - "${TFLIB_DIR}/../.." - "${TFLIB_DIR}/api" - "${TFLIB_DIR}/submodules/tflite-micro" - "${TFLIB_DIR}/submodules/flatbuffers/include" - PRIVATE - "src" - "${TFLIB_DIR}/.." - "${TFLIB_DIR}/submodules/tflite-micro" - "${TFLIB_DIR}/submodules/gemmlowp" - "${TFLIB_DIR}/submodules/ruy" - "${TFLIB_DIR}/src/tflite-xcore-kernels" -) - -target_link_libraries(inferencing_tflite_micro - PRIVATE - inferencing_lib_nn -) - -## suppress all linker warnings -target_link_options(inferencing_tflite_micro - INTERFACE - -Wl,-w -) - -add_dependencies(inferencing_tflite_micro lib_tflite_micro_patch) diff --git a/modules/inferencing/lib_nn b/modules/inferencing/lib_nn deleted file mode 160000 index f85b4804e..000000000 --- a/modules/inferencing/lib_nn +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f85b4804ea5f52f5fa4ca4b709a787ac62a8c526 diff --git a/modules/inferencing/lib_tflite_micro b/modules/inferencing/lib_tflite_micro deleted file mode 160000 index c59ee18f0..000000000 --- a/modules/inferencing/lib_tflite_micro +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c59ee18f013f159abaa10ef0faf70b18f80f0315 diff --git a/modules/io b/modules/io index dcf1a87dd..3263de1f9 160000 --- a/modules/io +++ b/modules/io @@ -1 +1 @@ -Subproject commit dcf1a87ddd006c328906094ec12493e604bc9b2f +Subproject commit 3263de1f960f25c6851ae49eacbbfb364bcc4eb5 diff --git a/modules/rtos b/modules/rtos index 9923425bf..446921136 160000 --- a/modules/rtos +++ b/modules/rtos @@ -1 +1 @@ -Subproject commit 9923425bfdfd494b2f49bd57b47caed98cde22ee +Subproject commit 44692113625a04d85377ce4c4c909635a1c68932 diff --git a/modules/sample_rate_conversion/lib_src b/modules/sample_rate_conversion/lib_src index e3bb06513..3b25970d8 160000 --- a/modules/sample_rate_conversion/lib_src +++ b/modules/sample_rate_conversion/lib_src @@ -1 +1 @@ -Subproject commit e3bb065134b52d0b16bb123a3d40c0761d30f2a5 +Subproject commit 3b25970d8842a71127473cc3c786e25973d271fd diff --git a/modules/sw_pll b/modules/sw_pll new file mode 160000 index 000000000..0a24b96f2 --- /dev/null +++ b/modules/sw_pll @@ -0,0 +1 @@ +Subproject commit 0a24b96f2a380d0ecb6c310de2c5e845dffbd894 diff --git a/modules/voice b/modules/voice index 8b80d3cf6..e230d556f 160000 --- a/modules/voice +++ b/modules/voice @@ -1 +1 @@ -Subproject commit 8b80d3cf684934f038b6ae3167a70cacfb6dd2c1 +Subproject commit e230d556f52d70bc3a09367c90bac35242351b59 diff --git a/modules/xscope_fileio/xscope_fileio b/modules/xscope_fileio/xscope_fileio index 52cff0826..10c696a47 160000 --- a/modules/xscope_fileio/xscope_fileio +++ b/modules/xscope_fileio/xscope_fileio @@ -1 +1 @@ -Subproject commit 52cff0826b2773beec49044a0729bb000c011379 +Subproject commit 10c696a47c3168704a749dd9d79f192ae42965f9 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..6968044f1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +# python_version 3.10 +# pip_version 24.* + +xmos-ai-tools==1.3.1 diff --git a/settings.yml b/settings.yml index 49014ccbd..3f19710d8 100644 --- a/settings.yml +++ b/settings.yml @@ -1,7 +1,7 @@ --- project: sln_voice title: XCORE-VOICE SOLUTION -version: 2.2.0 +version: 2.3.0 documentation: exclude_patterns_path: doc/exclude_patterns.inc diff --git a/test/asr/asr.cmake b/test/asr/asr.cmake index 217ec8c7e..77253c27c 100644 --- a/test/asr/asr.cmake +++ b/test/asr/asr.cmake @@ -44,10 +44,23 @@ if(${TEST_ASR} STREQUAL "SENSORY") set(APP_SOURCES ${APP_SOURCES} ${FFD_SRC_ROOT}/model/english_usa/command-pc62w-6.4.0-op10-prod-search.c - ) - set(MODEL_FILE ${FFD_SRC_ROOT}/model/english_usa/command-pc62w-6.4.0-op10-prod-net.bin.nibble_swapped) + ) + set(MODEL_FILE ${FFD_SRC_ROOT}/model/english_usa/command-pc62w-6.4.0-op10-prod-net.bin.nibble_swapped) set(TEST_ASR_LIBRARY_ID 0) set(TEST_ASR_NAME test_asr_sensory) + set(ASR_FLAG ASR_SENSORY=1) + +elseif(${TEST_ASR} STREQUAL "CYBERON") + message(STATUS "Building Cyberon ASR test") + set(ASR_LIBRARY sln_voice::app::asr::Cyberon) + set(ASR_BRICK_SIZE_SAMPLES 240) + set(APP_SOURCES + ${APP_SOURCES} + ) + set(MODEL_FILE ${FFD_SRC_ROOT}/model/english_usa/Hello_XMOS_pack_WithTxt.bin.Enc.NibbleSwap) + set(TEST_ASR_LIBRARY_ID 1) + set(TEST_ASR_NAME test_asr_cyberon) + set(ASR_FLAG ASR_CYBERON=1) else() message(FATAL_ERROR "Unable to build ${TEST_ASR} test") endif() @@ -72,21 +85,17 @@ set(APP_COMPILE_DEFINITIONS XUD_CORE_CLOCK=600 XSCOPE_HOST_IO_ENABLED=1 XSCOPE_HOST_IO_TILE=0 + ${ASR_FLAG} QSPI_FLASH_CALIBRATION_ADDRESS=${CALIBRATION_PATTERN_START_ADDRESS} QSPI_FLASH_MODEL_START_ADDRESS=${MODEL_START_ADDRESS} appconfASR_LIBRARY_ID=${TEST_ASR_LIBRARY_ID} appconfASR_BRICK_SIZE_SAMPLES=${ASR_BRICK_SIZE_SAMPLES} ) -if(${TEST_ASR} STREQUAL "SENSORY") - set(APP_COMPILE_DEFINITIONS - ${APP_COMPILE_DEFINITIONS} - ) -endif() - set(APP_LINK_OPTIONS -report ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope + -lotp3 ) set(APP_COMMON_LINK_LIBRARIES @@ -112,6 +121,7 @@ target_link_libraries(${TARGET_NAME} PUBLIC ${APP_COMMON_LINK_LIBRARIES} ${ASR_LIBRARY} + sln_voice::app::asr::device_memory ) target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) unset(TARGET_NAME) @@ -130,6 +140,7 @@ target_link_libraries(${TARGET_NAME} PUBLIC ${APP_COMMON_LINK_LIBRARIES} ${ASR_LIBRARY} + sln_voice::app::asr::device_memory ) target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) unset(TARGET_NAME) @@ -187,7 +198,7 @@ create_flash_app_target( # Create run target #********************** add_custom_target(run_${TEST_ASR_NAME} - COMMAND xrun --xscope-realtime --xscope-port localhost:12345 ${TEST_ASR_NAME}.xe + COMMAND xrun --xscope --xscope-port localhost:12345 ${TEST_ASR_NAME}.xe DEPENDS ${TEST_ASR_NAME} COMMENT "Run application" diff --git a/test/asr/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn b/test/asr/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn index b927e064e..b1284ff23 100644 --- a/test/asr/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn +++ b/test/asr/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn @@ -77,12 +77,10 @@ - + - - diff --git a/test/asr/check_asr.sh b/test/asr/check_asr.sh index ab00d71cd..0903ae86b 100755 --- a/test/asr/check_asr.sh +++ b/test/asr/check_asr.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (c) 2022, XMOS Ltd, All rights reserved +# Copyright (c) 2022-2024, XMOS Ltd, All rights reserved set -e # exit on first error set -x # echo on @@ -21,6 +21,18 @@ help() echo " h Print this Help." } +# Writes the XS3 TestMode register in the JTAG domain to reboot the device into JTAG-boot mode. +# Unsets the 'reboot' bit to release the chip from reset and waits for connection. +# Will be Fixed in XTC > 15.3.0 (Bugzilla ID 18895). +target_reset_reboot() { + local id=$1 + xgdb --batch \ + -ex "attach --id=${id}" \ + -ex "monitor sysreg write 0 8 8 0xA1006300" \ + -ex "monitor sysreg write 0 8 8 0x21006300" + sleep 5 # Fixed delay +} + # flag arguments while getopts h option do @@ -55,15 +67,23 @@ then DATA_PARTITION="dist/test_asr_sensory_data_partition.bin" TRIM_COMMAND="" # trim is not needed TRUTH_TRACK="${INPUT_DIR}/truth_labels.txt" +elif [[ ${ASR_LIBRARY} == "Cyberon" ]] +then + ASR_FIRMWARE="dist/test_asr_cyberon.xe" + DATA_PARTITION="dist/test_asr_cyberon_data_partition.bin" + TRIM_COMMAND="" # trim is not needed + TRUTH_TRACK="${INPUT_DIR}/truth_labels.txt" # elif [[ ${ASR_LIBRARY} == "Other" ]] # then # ASR_FIRMWARE="dist/test_asr_other.xe" # DATA_PARTITION="dist/test_asr_other_data_partition.bin" -# TRIM_COMMAND="trim 0 01:45" # need to trim input to account for 50 command limit +# TRIM_COMMAND="trim 0 01:45" # need to trim input to account for 50 command limit # TRUTH_TRACK="${INPUT_DIR}/truth_labels_1_45.txt" fi # flash the data partition file +target_reset_reboot 0 +target_reset_reboot 1 xflash ${ADAPTER_ID} --quad-spi-clock 50MHz --factory ${ASR_FIRMWARE} --boot-partition-size 0x100000 --data ${DATA_PARTITION} # read input list @@ -96,7 +116,7 @@ for ((j = 0; j < ${#INPUT_ARRAY[@]}; j += 1)); do PIPELINE_OUTPUT_CSV="${OUTPUT_DIR}/${FILE_NAME}_pipeline.csv" ASR_OUTPUT_LOG="${OUTPUT_DIR}/${FILE_NAME}_asr.log" SCORING_OUTPUT_LOG="${OUTPUT_DIR}/${FILE_NAME}_scoring.log" - + TEMP_XSCOPE_FILEIO_INPUT_WAV="${OUTPUT_DIR}/input.wav" TEMP_XSCOPE_FILEIO_OUTPUT_WAV="${OUTPUT_DIR}/output.wav" TEMP_XSCOPE_FILEIO_OUTPUT_LOG="${OUTPUT_DIR}/output.log" @@ -122,13 +142,15 @@ for ((j = 0; j < ${#INPUT_ARRAY[@]}; j += 1)); do rm ${TEMP_WAV} # call xrun (in background) - (xrun ${ADAPTER_ID} --xscope-realtime --xscope-port localhost:12345 ${PIPELINE_FIRMWARE}) & + target_reset_reboot 0 + target_reset_reboot 1 + (xrun ${ADAPTER_ID} --xscope --xscope-port localhost:12345 ${PIPELINE_FIRMWARE}) & # wait for app to load sleep 15 # run xscope host in directory where the TEMP_XSCOPE_FILEIO_INPUT_WAV resides - # xscope_host_endpoint is run in a subshell (inside parentheses) so when + # xscope_host_endpoint is run in a subshell (inside parentheses) so when # it exits, the xrun command above will also exit (cd ${OUTPUT_DIR} ; ${DIST_HOST}/xscope_host_endpoint 12345) @@ -151,13 +173,15 @@ for ((j = 0; j < ${#INPUT_ARRAY[@]}; j += 1)); do cp ${PROCESSED_WAV} ${TEMP_XSCOPE_FILEIO_INPUT_WAV} # call xrun (in background) - (xrun ${ADAPTER_ID} --xscope-realtime --xscope-port localhost:12345 ${ASR_FIRMWARE}) & + target_reset_reboot 0 + target_reset_reboot 1 + (xrun ${ADAPTER_ID} --xscope --xscope-port localhost:12345 ${ASR_FIRMWARE}) & # wait for app to load sleep 15 - + # run xscope host in directory where the TEMP_XSCOPE_FILEIO_INPUT_WAV resides - # xscope_host_endpoint is run in a subshell (inside parentheses) so when + # xscope_host_endpoint is run in a subshell (inside parentheses) so when # it exits, the xrun command above will also exit (cd ${OUTPUT_DIR} ; ${DIST_HOST}/xscope_host_endpoint 12345) @@ -181,11 +205,12 @@ for ((j = 0; j < ${#INPUT_ARRAY[@]}; j += 1)); do # log results echo "${INPUT_WAV}, ${MAX_ALLOWABLE_WER}, ${WER}" >> ${RESULTS} - # clean up temp + # clean up temp rm ${TEMP_XSCOPE_FILEIO_INPUT_WAV} rm ${TEMP_XSCOPE_FILEIO_OUTPUT_WAV} rm ${TEMP_XSCOPE_FILEIO_OUTPUT_LOG} -done + +done # print results cat ${RESULTS} diff --git a/test/asr/ffd_quick_cyberon.txt b/test/asr/ffd_quick_cyberon.txt new file mode 100644 index 000000000..77e368c59 --- /dev/null +++ b/test/asr/ffd_quick_cyberon.txt @@ -0,0 +1,5 @@ +# filename, Max allowable WER +ETSIRock_Speech54dB_Noise45dB 0.40 +Pink_Speech54dB_Noise45dB 0.37 +Pub_Speech54dB_Noise45dB 0.37 +Silence_Speech59dB 0.24 diff --git a/test/asr/ffd_quick.txt b/test/asr/ffd_quick_sensory.txt similarity index 62% rename from test/asr/ffd_quick.txt rename to test/asr/ffd_quick_sensory.txt index bdd5c9ced..cf7a7656d 100644 --- a/test/asr/ffd_quick.txt +++ b/test/asr/ffd_quick_sensory.txt @@ -1,5 +1,5 @@ # filename, Max allowable WER ETSIRock_Speech54dB_Noise45dB 0.25 -Pink_Speech54dB_Noise45dB 0.22 +Pink_Speech54dB_Noise45dB 0.23 Pub_Speech54dB_Noise45dB 0.30 -Silence_Speech59dB 0.04 +Silence_Speech59dB 0.06 diff --git a/test/asr/make_label_track.py b/test/asr/make_label_track.py index 2c4f3949d..7a745a94c 100755 --- a/test/asr/make_label_track.py +++ b/test/asr/make_label_track.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright 2022-2023 XMOS LIMITED. +# Copyright 2022-2024 XMOS LIMITED. # This Software is subject to the terms of the XMOS Public Licence: Version 1. # XMOS Public License: Version 1 @@ -30,6 +30,26 @@ 17: "Hello XMOS" } +CYBERON_LUT = { + 1: "Hello XMOS", + 2: "Switch on the TV", + 3: "Switch off the TV", + 4: "Channel up", + 5: "Channel down", + 6: "Volume up", + 7: "Volume down", + 8: "Switch on the lights", + 9: "Switch off the lights", + 10: "Brightness up", + 11: "Brightness down", + 12: "Switch on the lights", + 13: "Switch off the fan", + 14: "Speed up the fan", + 15: "Slow down the fan", + 16: "Set higher temperature", + 17: "Set lower temperature", +} + def convert(val): constructors = [int, float, str] for c in constructors: @@ -59,6 +79,8 @@ def process(log, label_track, lut): for recognition_event in recognition_events: if lut == "Sensory": event_str = SENSORY_LUT[recognition_event["id"]] + elif lut == "Cyberon": + event_str = CYBERON_LUT[recognition_event["id"]] else: event_str = str(recognition_event["id"]) @@ -70,7 +92,7 @@ def process(log, label_track, lut): parser = argparse.ArgumentParser('Label Track Maker') parser.add_argument('--log_file', help='Log file to parse') parser.add_argument('--label_track', help='Label track file') - parser.add_argument('--lut', choices={"Sensory"}, help='Lookup') + parser.add_argument('--lut', choices={"Sensory", "Cyberon"}, help='Lookup') args = parser.parse_args() process(args.log_file, args.label_track, args.lut) \ No newline at end of file diff --git a/test/asr/src/app_conf.h b/test/asr/src/app_conf.h index ee3cda859..b886e568a 100644 --- a/test/asr/src/app_conf.h +++ b/test/asr/src/app_conf.h @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef APP_CONF_H_ @@ -13,9 +13,9 @@ #ifndef appconfASR_BRICK_SIZE_SAMPLES #define appconfASR_BRICK_SIZE_SAMPLES 240 // typically set in asr.cmake -#endif +#endif -#ifndef appconfASR_MISSING_METADATA_CORRECTION +#ifndef appconfASR_MISSING_METADATA_CORRECTION #define appconfASR_MISSING_METADATA_CORRECTION (40 * appconfASR_BRICK_SIZE_SAMPLES) #endif @@ -31,4 +31,7 @@ #define appconfXSCOPE_IO_TASK_PRIORITY (configMAX_PRIORITIES - 1) #define appconfQSPI_FLASH_TASK_PRIORITY (configMAX_PRIORITIES - 1) +/* Maximum delay between a wake up phrase and command phrase */ +#define appconfINTENT_RESET_DELAY_MS 4000 + #endif /* APP_CONF_H_ */ diff --git a/test/asr/src/device_memory_impl.c b/test/asr/src/device_memory_impl.c deleted file mode 100644 index 680129a4c..000000000 --- a/test/asr/src/device_memory_impl.c +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2023 XMOS LIMITED. -// This Software is subject to the terms of the XMOS Public Licence: Version 1. -#include -#include -#include - -/* System headers */ -#include -#include -#include -#include - -/* FreeRTOS headers */ -#include "FreeRTOS.h" - -/* Library headers */ -#include "rtos_printf.h" - -/* App headers */ -#include "app_conf.h" -#include "platform/driver_instances.h" -#include "device_memory.h" -#include "device_memory_impl.h" - -void asr_printf(const char * format, ...) { - va_list args; - va_start(args, format); - xcore_utils_vprintf(format, args); - va_end(args); -} - -__attribute__((fptrgroup("devmem_malloc_fptr_grp"))) -void * devmem_malloc_local(size_t size) { - //rtos_printf("devmem_malloc_local size=%d\n", size); - return pvPortMalloc(size); -} - -__attribute__((fptrgroup("devmem_free_fptr_grp"))) -void devmem_free_local(void *ptr) { - vPortFree(ptr); -} - -__attribute__((fptrgroup("devmem_read_ext_fptr_grp"))) -void devmem_read_ext_local(void *dest, const void *src, size_t n) { - //rtos_printf("devmem_read_ext_local dest=0x%x src=0x%x size=%d\n", dest, src, n); - if (IS_FLASH(src)) { - // Need to subtract off XS1_SWMEM_BASE because qspi flash driver accounts for the offset - //uint32_t s = get_reference_time(); - rtos_qspi_flash_fast_read_mode_ll(qspi_flash_ctx, (uint8_t *)dest, (unsigned)(src - XS1_SWMEM_BASE), n, qspi_fast_flash_read_transfer_raw); - //uint32_t d = get_reference_time() - s; - //printf("%d, %0.01f (us), %0.04f (M/s)\n", n, d / 100.0f, (n / 1000000.0f ) / (d / 100000000.0f)); - } else { - memcpy(dest, src, n); - } -} - -void devmem_init(devmem_manager_t *devmem_ctx) { - xassert(devmem_ctx); - devmem_ctx->malloc = devmem_malloc_local; - devmem_ctx->free = devmem_free_local; - devmem_ctx->read_ext = devmem_read_ext_local; - devmem_ctx->read_ext_async = NULL; // not supported in this application - devmem_ctx->read_ext_wait = NULL; // not supported in this application -} diff --git a/test/asr/src/main.c b/test/asr/src/main.c index 5de75eb33..2459ed056 100644 --- a/test/asr/src/main.c +++ b/test/asr/src/main.c @@ -1,4 +1,4 @@ -// Copyright 2020-2023 XMOS LIMITED. +// Copyright 2020-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include @@ -51,7 +51,7 @@ void startup_task(void *arg) vTaskDelay(pdMS_TO_TICKS(1000)); #if ON_TILE(FLASH_TILE) -#if (appconfASR_LIBRARY_ID == 0) +#if (appconfASR_LIBRARY_ID == 0) || (appconfASR_LIBRARY_ID == 1) // Setup flash low-level mode // NOTE: must call rtos_qspi_flash_fast_read_shutdown_ll to use non low-level mode calls rtos_qspi_flash_fast_read_setup_ll(qspi_flash_ctx); diff --git a/test/asr/src/xscope_fileio_task.c b/test/asr/src/xscope_fileio_task.c index e96d368dd..e1ed75c32 100644 --- a/test/asr/src/xscope_fileio_task.c +++ b/test/asr/src/xscope_fileio_task.c @@ -1,4 +1,4 @@ -// Copyright 2022-2023 XMOS LIMITED. +// Copyright 2022-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #include @@ -9,7 +9,8 @@ #include "FreeRTOS.h" #include "task.h" #include "semphr.h" - +#include +#include #include "soc_xscope_host.h" #include "app_conf.h" @@ -25,24 +26,27 @@ #endif #if (appconfASR_LIBRARY_ID == 0) - // Sensory - + // Sensory only + // SEARCH model file is specified in the CMakeLists SENSORY_SEARCH_FILE variable extern const unsigned short gs_grammarLabel[]; void* grammar = (void*)gs_grammarLabel; - +#elif (appconfASR_LIBRARY_ID == 1) + void* grammar = NULL; +#else + #error "Unsupported appconfASR_LIBRARY_ID" +#endif +#if (appconfASR_LIBRARY_ID == 0) || (appconfASR_LIBRARY_ID == 1) // Model file is in flash at the offset specified in the CMakeLists // QSPI_FLASH_MODEL_START_ADDRESS variable. The XS1_SWMEM_BASE value needs - // to be added so the address in in the SwMem range. + // to be added so the address in in the SwMem range. uint16_t *model = (uint16_t *) (XS1_SWMEM_BASE + QSPI_FLASH_MODEL_START_ADDRESS); -#else - #error "Unsupported appconfASR_LIBRARY_ID" #endif static TaskHandle_t xscope_fileio_task_handle; static xscope_file_t infile; static xscope_file_t outfile; -static asr_port_t asr_ctx; +static asr_port_t asr_ctx; static devmem_manager_t devmem_ctx; static char log_buffer[1024]; @@ -63,6 +67,16 @@ void xscope_fileio_lock_release(void) { } void init_xscope_host_data_user_cb(chanend_t c_host) { + + // Delay the xscope initialization by 1 ms, + // to avoid the problem described in https://github.com/xmos/sln_voice/issues/349 + hwtimer_t tmr = hwtimer_alloc(); + { + xassert(tmr != 0); + hwtimer_delay(tmr, 100000); // 1ms with 100 MHz timer tick + } + hwtimer_free(tmr); + xscope_io_init(c_host); } #endif @@ -85,7 +99,7 @@ void xscope_fileio_task(void *arg) { wav_header input_header_struct; unsigned input_header_size; unsigned frame_count; - unsigned brick_count; + unsigned brick_count; uint32_t DWORD_ALIGNED in_buf_raw_32[appconfASR_BRICK_SIZE_SAMPLES * appconfINPUT_CHANNELS]; int16_t DWORD_ALIGNED in_buf_int_16[appconfINPUT_CHANNELS * appconfASR_BRICK_SIZE_SAMPLES]; size_t bytes_read = 0; @@ -101,8 +115,7 @@ void xscope_fileio_task(void *arg) { infile = xscope_open_file(appconfINPUT_FILENAME, "rb"); // Validate input wav file if(get_wav_header_details(&infile, &input_header_struct, &input_header_size) != 0){ - rtos_printf("Error: error in get_wav_header_details()\n"); - _Exit(1); + xassert(0 && "Error: error in get_wav_header_details()\n"); } xscope_fseek(&infile, input_header_size, SEEK_SET); vTaskDelay(pdMS_TO_TICKS(1000)); @@ -114,17 +127,17 @@ void xscope_fileio_task(void *arg) { if(input_header_struct.bit_depth != appconfSAMPLE_BIT_DEPTH) { rtos_printf("Error: unsupported wav bit depth (%d) for %s file. Only 32 supported\n", input_header_struct.bit_depth, appconfINPUT_FILENAME); - _Exit(1); + xassert(0); } - // Ensure input wav file contains correct number of channels + // Ensure input wav file contains correct number of channels if(input_header_struct.num_channels != appconfINPUT_CHANNELS){ rtos_printf("Error: wav num channels(%d) does not match (%u)\n", input_header_struct.num_channels, appconfINPUT_CHANNELS); - _Exit(1); + xassert(0); } - + // Calculate number of frames in the wav file frame_count = wav_get_num_frames(&input_header_struct); - brick_count = frame_count / appconfASR_BRICK_SIZE_SAMPLES; + brick_count = frame_count / appconfASR_BRICK_SIZE_SAMPLES; // Init ASR library devmem_init(&devmem_ctx); @@ -165,40 +178,42 @@ void xscope_fileio_task(void *arg) { // Send audio to ASR asr_error = asr_process(asr_ctx, in_buf_int_16, appconfASR_BRICK_SIZE_SAMPLES); - if (asr_error != ASR_OK) continue; + if (asr_error != ASR_OK) continue; asr_error = asr_get_result(asr_ctx, &asr_result); - if (asr_error != ASR_OK) continue; + if (asr_error != ASR_OK) continue; // Query or compute recognition event metadata size_t start_index; size_t end_index; size_t duration; - + if (asr_result.id > 0) { - if (asr_result.start_index > 0) { - start_index = asr_result.start_index; + + if (asr_result.end_index > 0) { + end_index = asr_result.end_index; } else { - // No metadata so assume this brick - appconfASR_MISSING_START_METADATA_CORRECTION - start_index = (b * appconfASR_BRICK_SIZE_SAMPLES) - appconfASR_MISSING_METADATA_CORRECTION; + // No metadata so assume this brick - appconfASR_MISSING_START_METADATA_CORRECTION / 2 + end_index = (b * appconfASR_BRICK_SIZE_SAMPLES) - appconfASR_MISSING_METADATA_CORRECTION / 2; } - if (asr_result.end_index > 0) { - end_index = asr_result.end_index; + if (asr_result.start_index > 0) { + start_index = asr_result.start_index; } else { - // No metadata so assume start_index - end_index = start_index; + // No metadata so assume the end_index - (2 * appconfASR_MISSING_START_METADATA_CORRECTION) + // The average duration of the detection is 1.16 ms, and (2 * appconfASR_MISSING_START_METADATA_CORRECTION) is 1.2 ms + start_index = end_index - 2 * appconfASR_MISSING_METADATA_CORRECTION; } if (asr_result.duration > 0) { - duration = asr_result.duration; + duration = asr_result.duration; } else { // No metadata so assume no duration - duration = 0; + duration = -1; } // Log result - sprintf(log_buffer, "RECOGNIZED: id=%d, start=%d, end=%d, duration=%d\n", + sprintf(log_buffer, "RECOGNIZED: id=%d, start=%d, end=%d, duration=%d\n", asr_result.id, start_index, end_index, @@ -223,9 +238,7 @@ void xscope_fileio_task(void *arg) { xscope_close_all_files(); } rtos_osal_critical_exit(state); - - /* Close the app */ - _Exit(0); + exit(0); // exit syscall can cause issues with XTC 15.3.0 if called from both tiles } void xscope_fileio_tasks_create(unsigned priority, void* app_data) { @@ -235,10 +248,10 @@ void xscope_fileio_tasks_create(unsigned priority, void* app_data) { app_data, priority, &xscope_fileio_task_handle); - + // Define the core affinity mask such that this task can only run on a specific core UBaseType_t uxCoreAffinityMask = 0x10; /* Set the core affinity mask for the task. */ - vTaskCoreAffinitySet( xscope_fileio_task_handle, uxCoreAffinityMask ); + vTaskCoreAffinitySet( xscope_fileio_task_handle, uxCoreAffinityMask ); } diff --git a/test/device_firmware_update/check_dfu.sh b/test/device_firmware_update/check_dfu.sh index 8f6231702..78cca5bee 100755 --- a/test/device_firmware_update/check_dfu.sh +++ b/test/device_firmware_update/check_dfu.sh @@ -50,7 +50,7 @@ fi # reset board -xgdb -batch -ex "connect ${ADAPTER_ID} --reset-to-mode-pins" -ex detach +xrun --reset ${ADAPTER_ID} # flash the data partition # build_tests.sh creates example_ffva_ua_adec_altarch_data_partition.bin used here @@ -78,7 +78,7 @@ xflash ${ADAPTER_ID} --factory-version ${XTC_VERSION_MAJOR}.${XTC_VERSION_MINOR} dfu-util -e -d ${USB_VID}:${USB_PID} -a 1 -D ${OUTPUT_DIR}/${FIRMWARE_NAME}_upgrade.bin # reset board -xgdb -batch -ex "connect ${ADAPTER_ID} --reset-to-mode-pins" -ex detach +xrun --reset ${ADAPTER_ID} # wait for dust to gather sleep 5 @@ -88,4 +88,3 @@ dfu-util -e -d ${USB_VID}:${USB_PID} -a 1 -U ${OUTPUT_DIR}/readback_upgrade.bin # cleanup afterwards so we don't leave an image on the flash. Leaving an image may cause issues as we have multiple targets xflash ${ADAPTER_ID} --erase-all --target-file "${SLN_VOICE_ROOT}"/examples/ffd/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn - diff --git a/test/device_firmware_update/check_dfu_i2c.sh b/test/device_firmware_update/check_dfu_i2c.sh new file mode 100644 index 000000000..a07ce8bd3 --- /dev/null +++ b/test/device_firmware_update/check_dfu_i2c.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +# To run this test do the following: +# 1. Configure a Rapsberry-Pi: +# a. Follow the instructions for XVF3800-INT on https://github.com/xmos/vocalfusion-rpi-setup?tab=readme-ov-file#setup +# b. Clone on the Raspberry Pi the repo host_xvf_control using `git clone https://github.com/xmos/host_xvf_control` +# c. In the file host_xvf_control/src/dfu/transport_config.yaml update the value of I2C_ADDRESS from 0x2C to 0x42 +# d. Build the xvf_dfu host application on the Raspberry-Pi using the instructions in https://github.com/xmos/host_xvf_control/blob/main/README.rst +# 2. Prepare the hardware +# a. Attach an XK-VOICE-L71 board to the Raspberry-Pi expander +# b. Connect an xTAG to XK-VOICE-L71 board and to a host machine +# 3. Build the application example_ffva_int_fixed_delay and flash it to the board: +# - on Linux/macOS: +# cmake -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake +# cd build +# make flash_app_example_ffva_int_fixed_delay +# - on Windows: +# cmake -G Ninja -B build --toolchain=xmos_cmake_toolchain/xs3a.cmake +# cd build +# ninja flash_app_example_ffva_int_fixed_delay +# 4. Change the value of APP_VERSION_MAJOR in app_conf.h and generate an upgrade image: +# - on Linux/macOS: +# cd build +# make create_upgrade_img_example_ffva_int_fixed_delay +# mv example_ffva_int_fixed_delay_upgrade.bin download1.bin +# - on Windows: +# cd build +# ninja create_upgrade_img_example_ffva_int_fixed_delay +# MOVE example_ffva_int_fixed_delay_upgrade.bin download1.bin +# 5. Change the value again of APP_VERSION_MAJOR in app_conf.h and generate an upgrade image: +# - on Linux/macOS: +# cd build +# make create_upgrade_img_example_ffva_int_fixed_delay +# mv example_ffva_int_fixed_delay_upgrade.bin download2.bin +# - on Windows: +# cd build +# ninja create_upgrade_img_example_ffva_int_fixed_delay +# MOVE example_ffva_int_fixed_delay_upgrade.bin download2.bin +# 6. Copy the files download1.bin, download2.bin, emptyfile.bin and check_dfu_i2c.sh to the host_xvf_control/build folder on the Raspberry-Pi +# 7. On the Raspberry-Pi, set the desired value of ITERATION_NUM in check_dfu_i2c.sh +# 8. On the Raspberry-Pi, run this script from the host_xvf_control build folder: +# source check_dfu_i2c.sh + +ITERATION_NUM=2 +UPGRADE_FILE_1="download1.bin" +UPGRADE_FILE_2="download2.bin" +EMPTY_FILE="emptyfile.bin" +UPLOAD_FILE="upload.bin" + +check_upgrade() { + + # Download upgrade image + ./xvf_dfu --download $1 + + # Reboot the device + ./xvf_dfu --reboot + + # 3s delay + sleep 3 + + # Read app version, just for debugging + ./xvf_dfu --version + + # Upload upgrade image + ./xvf_dfu --upload-upgrade $UPLOAD_FILE + + # Compare uploaded and downloaded images + upload_size=$(stat -c '%s' $UPLOAD_FILE) + # The uploaded file is not padded, + # so don't include the padding of the downloaded image + cmp -n $upload_size $UPLOAD_FILE $1 + if [[ $? == 0 ]]; then + echo "Upload of $1 is correct" + else + echo "Upload of $1 is incorrect" + exit 1 + fi + + # Delete uploaded images + rm $UPLOAD_FILE + + # 1s delay + sleep 1 +} + +counter=0 + +# Checking if necessary files exist +if [ ! -f $UPGRADE_FILE_1 ]; then + echo "File $UPGRADE_FILE_1 doesn't exist." + exit -1 +fi +if [ ! -f $UPGRADE_FILE_2 ]; then + echo "File $UPGRADE_FILE_2 doesn't exist." + exit -1 +fi +if [ ! -f $EMPTY_FILE ]; then + echo "File $EMPTY_FILE doesn't exist." + exit -1 +fi + +while [ $counter -lt $ITERATION_NUM ] +do + counter=$(( $counter + 1 )) + echo "------------------------" + echo "DFU attempt number $counter" + echo "------------------------" + + # Download first upgrade image + check_upgrade $UPGRADE_FILE_1 + + # Download second upgrade image + check_upgrade $UPGRADE_FILE_2 + + # Download empty upgrade image + check_upgrade $EMPTY_FILE + +done diff --git a/test/device_firmware_update/emptyfile.bin b/test/device_firmware_update/emptyfile.bin new file mode 100644 index 000000000..08e7df176 Binary files /dev/null and b/test/device_firmware_update/emptyfile.bin differ diff --git a/test/ffd_gpio/XCORE-AI-EXPLORER.xn b/test/ffd_gpio/XCORE-AI-EXPLORER.xn index db710c9ea..7331171b5 100644 --- a/test/ffd_gpio/XCORE-AI-EXPLORER.xn +++ b/test/ffd_gpio/XCORE-AI-EXPLORER.xn @@ -100,12 +100,10 @@ - + - - diff --git a/test/ffd_gpio/gpio.cmake b/test/ffd_gpio/gpio.cmake index 295418200..79ebc16c7 100644 --- a/test/ffd_gpio/gpio.cmake +++ b/test/ffd_gpio/gpio.cmake @@ -2,7 +2,7 @@ # Gather Sources #********************** file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c) -list(APPEND APP_SOURCES ${SOLUTION_VOICE_ROOT_PATH}/examples/ffd/src/intent_handler/intent_handler.c) +list(APPEND APP_SOURCES ${SOLUTION_VOICE_ROOT_PATH}/modules/asr/intent_handler/intent_handler.c) set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src ${CMAKE_CURRENT_LIST_DIR}/src/dummy_headers ${SOLUTION_VOICE_ROOT_PATH}/modules/asr @@ -64,6 +64,7 @@ target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES}) target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES}) target_compile_definitions(${TARGET_NAME} PUBLIC ${APP_COMPILE_DEFINITIONS} THIS_XCORE_TILE=0) target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) + target_link_libraries(${TARGET_NAME} PUBLIC core::general rtos::freertos rtos::drivers::audio) target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) unset(TARGET_NAME) diff --git a/test/ffd_gpio/src/app_conf.h b/test/ffd_gpio/src/app_conf.h index 52bc31d5e..94a75cbb7 100644 --- a/test/ffd_gpio/src/app_conf.h +++ b/test/ffd_gpio/src/app_conf.h @@ -1,4 +1,4 @@ -// Copyright 2021-2023 XMOS LIMITED. +// Copyright 2021-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef APP_CONF_H_ @@ -15,10 +15,8 @@ #define I2C_SLAVE_CORE_MASK (1 << 3) #define I2C_SLAVE_ADDR 0x7A -#define appconfINTENT_I2C_OUTPUT_DEVICE_ADDR I2C_SLAVE_ADDR - #define appconfAUDIO_PLAYBACK_ENABLED 0 -#define appconfINTENT_I2C_OUTPUT_ENABLED 0 +#define appconfINTENT_I2C_MASTER_OUTPUT_ENABLED 0 #define appconfINTENT_UART_OUTPUT_ENABLED 0 #define ASR_TILE_NO 0 diff --git a/test/ffd_gpio/src/main.c b/test/ffd_gpio/src/main.c index 97c46721b..0802f0f3d 100644 --- a/test/ffd_gpio/src/main.c +++ b/test/ffd_gpio/src/main.c @@ -65,7 +65,7 @@ void vWD(void *arg) vTaskDelay(10); test_printf("Host Timeout"); test_printf("FAIL"); - _Exit(0); + exit(0); } #if ON_TILE(1) @@ -152,8 +152,7 @@ void vApplicationDaemonTaskStartup(void *arg) sync(other_tile_c); test_printf("PASS GPIO"); - - _Exit(0); + exit(0); #endif chanend_free(other_tile_c); diff --git a/test/ffd_low_power_audio_buffer/src/app_conf.h b/test/ffd_low_power_audio_buffer/src/app_conf.h index 4bac02c1f..388b5a65c 100644 --- a/test/ffd_low_power_audio_buffer/src/app_conf.h +++ b/test/ffd_low_power_audio_buffer/src/app_conf.h @@ -1,4 +1,4 @@ -// Copyright 2023 XMOS LIMITED. +// Copyright 2023-2024 XMOS LIMITED. // This Software is subject to the terms of the XMOS Public Licence: Version 1. #ifndef APP_CONF_H @@ -14,7 +14,7 @@ #define ON_TILE(t) (!defined(THIS_XCORE_TILE) || THIS_XCORE_TILE == (t)) #endif /* __XC__ */ -#define AUDIO_PIPELINE_TILE_NO 1 +#define AUDIO_PIPELINE_OUTPUT_TILE_NO 1 #define appconfAUDIO_PIPELINE_BUFFER_ENABLED 1 #define appconfAUDIO_PIPELINE_BUFFER_NUM_FRAMES 32 #define appconfAUDIO_PIPELINE_FRAME_ADVANCE 240 diff --git a/test/pipeline/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn b/test/pipeline/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn index b927e064e..b1284ff23 100644 --- a/test/pipeline/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn +++ b/test/pipeline/bsp_config/XK_VOICE_L71/XK_VOICE_L71.xn @@ -77,12 +77,10 @@ - + - - diff --git a/test/pipeline/check_pipeline.sh b/test/pipeline/check_pipeline.sh index c12191270..d6b86fdeb 100755 --- a/test/pipeline/check_pipeline.sh +++ b/test/pipeline/check_pipeline.sh @@ -77,6 +77,18 @@ echo "***********************************" echo "Log file: ${RESULTS}" echo "***********************************" +# Writes the XS3 TestMode register in the JTAG domain to reboot the device into JTAG-boot mode. +# Unsets the 'reboot' bit to release the chip from reset and waits for connection. +# Will be Fixed in XTC > 15.3.0 (Bugzilla ID 18895). +target_reset_reboot() { + local id=$1 + xgdb --batch \ + -ex "attach --id=${id}" \ + -ex "monitor sysreg write 0 8 8 0xA1006300" \ + -ex "monitor sysreg write 0 8 8 0x21006300" + sleep 5 # Fixed delay +} + for ((j = 0; j < ${#INPUT_ARRAY[@]}; j += 1)); do read -ra FIELDS <<< ${INPUT_ARRAY[j]} FILE_NAME=${FIELDS[0]} @@ -110,9 +122,11 @@ for ((j = 0; j < ${#INPUT_ARRAY[@]}; j += 1)); do # remix and create input wav to the filename expected for xscope_fileio (input.wav) sox ${INPUT_WAV} --no-dither -r 16000 -b 32 ${XSCOPE_FILEIO_INPUT_WAV} ${REMIX_PATTERN} - + # call xrun (in background) - xrun ${ADAPTER_ID} --xscope-realtime --xscope-port localhost:12345 ${FIRMWARE} & + target_reset_reboot 0 + target_reset_reboot 1 + xrun ${ADAPTER_ID} --xscope --xscope-port localhost:12345 ${FIRMWARE} & # wait for app to load sleep 10 @@ -149,6 +163,7 @@ for ((j = 0; j < ${#INPUT_ARRAY[@]}; j += 1)); do rm "${OUTPUT_DIR}/${AMAZON_WAV}" rm ${XSCOPE_FILEIO_INPUT_WAV} rm ${XSCOPE_FILEIO_OUTPUT_WAV} + done # clean up diff --git a/test/pipeline/pipeline.cmake b/test/pipeline/pipeline.cmake index 2d6130572..47b85a925 100644 --- a/test/pipeline/pipeline.cmake +++ b/test/pipeline/pipeline.cmake @@ -129,7 +129,7 @@ merge_binaries(${TEST_PIPELINE_NAME} tile0_${TEST_PIPELINE_NAME} tile1_${TEST_PI # Create run and debug targets #********************** add_custom_target(run_${TEST_PIPELINE_NAME} - COMMAND xrun --xscope-realtime --xscope-port localhost:12345 ${TEST_PIPELINE_NAME}.xe + COMMAND xrun --xscope --xscope-port localhost:12345 ${TEST_PIPELINE_NAME}.xe DEPENDS ${TEST_PIPELINE_NAME} COMMENT "Run application" diff --git a/test/pipeline/src/xscope_fileio_task.c b/test/pipeline/src/xscope_fileio_task.c index c32829e53..cd7990b73 100644 --- a/test/pipeline/src/xscope_fileio_task.c +++ b/test/pipeline/src/xscope_fileio_task.c @@ -6,6 +6,8 @@ #include #include +#include + #include "FreeRTOS.h" #include "task.h" #include "semphr.h" @@ -92,7 +94,7 @@ void xscope_fileio_task(void *arg) { // Validate input wav file if(get_wav_header_details(&audio_infile, &input_header_struct, &input_header_size) != 0){ rtos_printf("Error: error in get_wav_header_details()\n"); - _Exit(1); + xassert(0); } xscope_fseek(&audio_infile, input_header_size, SEEK_SET); } @@ -102,12 +104,12 @@ void xscope_fileio_task(void *arg) { if(input_header_struct.bit_depth != appconfSAMPLE_BIT_DEPTH) { rtos_printf("Error: unsupported wav bit depth (%d) for %s file. Only 32 supported\n", input_header_struct.bit_depth, appconfINPUT_FILENAME); - _Exit(1); + xassert(0); } // Ensure input wav file contains correct number of channels if(input_header_struct.num_channels != appconfAUDIO_PIPELINE_INPUT_CHANNELS){ rtos_printf("Error: wav num channels(%d) does not match (%u)\n", input_header_struct.num_channels, appconfAUDIO_PIPELINE_INPUT_CHANNELS); - _Exit(1); + xassert(0); } // Calculate number of frames in the wav file @@ -200,9 +202,7 @@ void xscope_fileio_task(void *arg) { xscope_close_all_files(); } rtos_osal_critical_exit(state); - - /* Close the app */ - _Exit(0); + exit(0); } void xscope_fileio_tasks_create(unsigned priority, void* app_data) { diff --git a/test/requirements.txt b/test/requirements.txt index de8cd8375..b9dc69778 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -1,9 +1,10 @@ -e git+https://github.com/xmos/audio_test_tools@develop#egg=audio_test_tools&subdirectory=python matplotlib==3.3.1 -numpy==1.19.5 +numpy>=1.19.5,<2 pylint==2.5.3 -pytest==6.0.0 +pytest>6,<=8 pytest-xdist==1.34.0 scipy==1.10.1 soundfile==0.11.0 pyserial==3.5 +xmos-ai-tools==1.3.1 diff --git a/test/sample_rate_conversion/check_sample_rate_conversion.sh b/test/sample_rate_conversion/check_sample_rate_conversion.sh index 44c4867ca..12cba8da5 100755 --- a/test/sample_rate_conversion/check_sample_rate_conversion.sh +++ b/test/sample_rate_conversion/check_sample_rate_conversion.sh @@ -81,4 +81,4 @@ echo " OUTPUT_WAV="${OUTPUT_WAV} echo " LENGTH="${LENGTH} # reset board for the next test -xgdb -batch -ex "connect ${ADAPTER_ID} --reset-to-mode-pins" -ex detach +xrun --reset ${ADAPTER_ID} diff --git a/tools/ci/build_examples.sh b/tools/ci/build_examples.sh index 4c0106ec8..601ccf470 100755 --- a/tools/ci/build_examples.sh +++ b/tools/ci/build_examples.sh @@ -35,6 +35,7 @@ XCORE_VOICE_ROOT=`git rev-parse --show-toplevel` source ${XCORE_VOICE_ROOT}/tools/ci/helper_functions.sh export_ci_build_vars +setup_python_env "${XCORE_VOICE_ROOT}" # setup distribution folder DIST_DIR=${XCORE_VOICE_ROOT}/dist @@ -74,4 +75,9 @@ for ((i = 0; i < ${#examples[@]}; i += 1)); do (cd ${path}/build_${board}; log_errors $CI_BUILD_TOOL make_data_partition_${app_target} $CI_BUILD_TOOL_ARGS) (cd ${path}/build_${board}; cp ${app_target}_data_partition.bin ${DIST_DIR}) fi + echo '******************************************************' + echo '* Add extra files' + echo '******************************************************' + cd ${path}; cp LICENSE.rst ${DIST_DIR} + cd ${path}; cp README.rst ${DIST_DIR} done diff --git a/tools/ci/build_tests.sh b/tools/ci/build_tests.sh index eaac26189..93dfaee41 100755 --- a/tools/ci/build_tests.sh +++ b/tools/ci/build_tests.sh @@ -6,6 +6,9 @@ XCORE_VOICE_ROOT=`git rev-parse --show-toplevel` source ${XCORE_VOICE_ROOT}/tools/ci/helper_functions.sh export_ci_build_vars +# Call the Python setup function (only needed if venv is not active) +# setup_python_env "${XCORE_VOICE_ROOT}" + # setup distribution folder DIST_DIR=${XCORE_VOICE_ROOT}/dist DIST_HOST_DIR=${XCORE_VOICE_ROOT}/dist_host @@ -26,6 +29,7 @@ tests=( "test_pipeline_ffd test_pipeline_ffd NONE TEST_PIPELINE=FFD XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake" "test_pipeline_ffva_adec_altarch test_pipeline_ffva_adec_altarch NONE TEST_PIPELINE=FFVA_ALT_ARCH XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake" "test_asr_sensory test_asr_sensory test_asr_sensory TEST_ASR=SENSORY XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake" + "test_asr_cyberon test_asr_cyberon test_asr_cyberon TEST_ASR=CYBERON XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake" "test_ffva_sample_rate_conv example_ffva_ua_adec_altarch example_ffva_ua_adec_altarch DEBUG_FFVA_USB_MIC_INPUT_PIPELINE_BYPASS=1 XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake" "test_ffva_verbose_output example_ffva_ua_adec_altarch example_ffva_ua_adec_altarch DEBUG_FFVA_USB_VERBOSE_OUTPUT=1 XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake" "test_ffd_gpio test_ffd_gpio NONE NONE XCORE_AI_EXPLORER xmos_cmake_toolchain/xs3a.cmake" diff --git a/tools/ci/helper_functions.sh b/tools/ci/helper_functions.sh index 9eefd1718..0151f1220 100755 --- a/tools/ci/helper_functions.sh +++ b/tools/ci/helper_functions.sh @@ -57,6 +57,24 @@ function export_ci_build_vars { export CI_BUILD_TOOL_ARGS="" else export CI_BUILD_TOOL="make" - export CI_BUILD_TOOL_ARGS="-j" + export CI_BUILD_TOOL_ARGS="-j$(nproc)" + fi +} + +# Function to set up Python environment and install dependencies +function setup_python_env() { + local root=$1 + local venv_dir="${root}/.venv" + local req_file="${root}/requirements.txt" + + # Check if virtual environment exists, if not, create it + if [ ! -d "${venv_dir}" ]; then + echo "Creating Python virtual environment in ${venv_dir}..." + python3 -m venv "${venv_dir}" + # Activate the virtual environment + echo "Activating virtual environment in ${venv_dir}..." + source "${venv_dir}/bin/activate" + pip install --no-cache-dir xmos_ai_tools + echo "Python environment setup complete." fi } diff --git a/tools/ci/main_examples.txt b/tools/ci/main_examples.txt index 4df9c6c09..be629b99e 100644 --- a/tools/ci/main_examples.txt +++ b/tools/ci/main_examples.txt @@ -1,8 +1,10 @@ -ffva_ua_adec_altarch example_ffva_ua_adec_altarch Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake -ffva_int_fixed_delay example_ffva_int_fixed_delay Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake -low_lower_ffd_sensory example_low_power_ffd_sensory Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake -ffd_sensory example_ffd_sensory Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake -ffd_cyberon example_ffd_cyberon Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake -mic_aggregator_TDM example_mic_aggregator_tdm No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake -mic_aggregator_USB example_mic_aggregator_usb No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake -asrc example_asrc_demo No XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake +ffva_ua_adec_altarch example_ffva_ua_adec_altarch Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake +ffva_int_fixed_delay example_ffva_int_fixed_delay Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake +ffva_int_cyberon_fixed_delay example_ffva_int_cyberon_fixed_delay Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake +low_lower_ffd_sensory example_low_power_ffd_sensory Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake +ffd_sensory example_ffd_sensory Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake +ffd_cyberon example_ffd_cyberon Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake +ffd_i2s_input_cyberon example_ffd_i2s_input_cyberon Yes XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake +mic_aggregator_TDM example_mic_aggregator_tdm No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake +mic_aggregator_USB example_mic_aggregator_usb No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake +asrc example_asrc_demo No XK_VOICE_L71 xmos_cmake_toolchain/xs3a.cmake