diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 24782419d..b6af7e587 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -22,7 +22,7 @@ on: workflow_dispatch: {} env: - DOC_BUILDER_IMAGE: 'ghcr.io/xmos/doc_builder:main' + DOC_BUILDER_IMAGE: 'ghcr.io/xmos/doc_builder:latest' jobs: build_documentation: diff --git a/.gitmodules b/.gitmodules index f79adf2c4..651b28cac 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "frameworks/rtos"] path = modules/rtos url = git@github.com:xmos/fwk_rtos.git +[submodule "modules/xscope_fileio/xscope_fileio"] + path = modules/xscope_fileio/xscope_fileio + url = git@github.com:xmos/xscope_fileio.git diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ae364ff7..52de360c7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,17 @@ XCORE SDK change log ==================== +0.12.0 +------ + + * Addition of FreeRTOS Tracealyzer example application + * Addition of FreeRTOS DFU example application + * Addition of FreeRTOS xscope_fileio example application + * Addition of FreeRTOS xlink example application + * Addition of Voice framework module + * Removed FreeRTOS Dispatcher example application + * Minor documentation updates + 0.11.0 ------ diff --git a/Jenkinsfile b/Jenkinsfile index d3bbb2474..00c43a9dd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,14 +1,4 @@ -@Library('xmos_jenkins_shared_library@v0.18.0') _ - -def withXTAG(String target, Closure body) { - // Acquire an xtag adapter-id by target name - def adapterID = sh (script: "xtagctl acquire ${target}", returnStdout: true).trim() - // Run the closure - body(adapterID) - // Release the xtag by adapter-id - sh ("xtagctl release ${adapterID}") -} - +@Library('xmos_jenkins_shared_library@v0.20.0') _ // Wait here until specified artifacts appear def artifactUrls = getGithubArtifactUrls([ @@ -23,7 +13,7 @@ getApproval() pipeline { agent { - label 'sdk' + label 'us-hw-xcai-exp0' } options { disableConcurrentBuilds() @@ -45,7 +35,7 @@ pipeline { environment { PYTHON_VERSION = "3.8.11" VENV_DIRNAME = ".venv" - DOWNLOAD_DIRNAME = "build" + DOWNLOAD_DIRNAME = "dist" SDK_TEST_RIG_TARGET = "xcore_sdk_test_rig" } stages { @@ -93,8 +83,8 @@ pipeline { withVenv { script { if (fileExists("$DOWNLOAD_DIRNAME/example_freertos_getting_started.xe")) { - withXTAG("$SDK_TEST_RIG_TARGET") { adapterID -> - sh "test/examples/run_freertos_getting_started_tests.sh $adapterID" + withXTAG(["$SDK_TEST_RIG_TARGET"]) { adapterIDs -> + sh "test/examples/run_freertos_getting_started_tests.sh " + adapterIDs[0] } } else { echo 'SKIPPED: example_freertos_getting_started' @@ -102,35 +92,36 @@ pipeline { } script { if (fileExists("$DOWNLOAD_DIRNAME/example_freertos_explorer_board.xe")) { - withXTAG("$SDK_TEST_RIG_TARGET") { adapterID -> - sh "test/examples/run_freertos_explorer_board_tests.sh $adapterID" + withXTAG(["$SDK_TEST_RIG_TARGET"]) { adapterIDs -> + sh "test/examples/run_freertos_explorer_board_tests.sh " + adapterIDs[0] } } else { echo 'SKIPPED: example_freertos_explorer_board' } } script { - if (fileExists("$DOWNLOAD_DIRNAME/example_freertos_dispatcher.xe")) { - withXTAG("$SDK_TEST_RIG_TARGET") { adapterID -> - sh "test/examples/run_freertos_dispatcher_tests.sh $adapterID" + if (fileExists("$DOWNLOAD_DIRNAME/example_freertos_l2_cache.xe")) { + withXTAG(["$SDK_TEST_RIG_TARGET"]) { adapterIDs -> + sh "test/examples/run_freertos_l2_cache_tests.sh " + adapterIDs[0] } } else { - echo 'SKIPPED: example_freertos_dispatcher' + echo 'SKIPPED: example_freertos_l2_cache' } } script { - if (fileExists("$DOWNLOAD_DIRNAME/example_freertos_l2_cache.xe")) { - withXTAG("$SDK_TEST_RIG_TARGET") { adapterID -> - sh "test/examples/run_freertos_l2_cache_tests.sh $adapterID" + if (fileExists("$DOWNLOAD_DIRNAME/example_freertos_tracealyzer.xe")) { + withXTAG(["$SDK_TEST_RIG_TARGET"]) { adapterIDs -> + sh "test/examples/run_freertos_tracealyzer_tests.sh " + adapterIDs[0] } } else { - echo 'SKIPPED: example_freertos_l2_cache' + echo 'SKIPPED: example_freertos_tracealyzer' } - } + } } } } } + // stage('Run bare-metal examples') { // steps { // withTools(params.TOOLS_VERSION) { diff --git a/README.md b/README.md index 232956276..2c3bb0141 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Download and install the xcore [XTC Tools](https://www.xmos.ai/software-tools/) ## Documentation -See the [official documentation](https://www.xmos.com/documentation/XM-014660-PC-2/html/) for more information including: +See the [official documentation](https://www.xmos.ai/documentation/XM-014660-PC-2/html/) for more information including: - Instructions for installing - Getting started guides diff --git a/doc/README.rst b/doc/README.rst index 7a6678f99..3c7908c3a 100644 --- a/doc/README.rst +++ b/doc/README.rst @@ -25,7 +25,7 @@ Pull the docker container: .. code-block:: console - docker pull ghcr.io/xmos/doc_builder:main + docker pull ghcr.io/xmos/doc_builder:latest ======== Building @@ -35,7 +35,7 @@ To build the documentation, run the following command in the root of the reposit .. code-block:: console - docker run --rm -t -u "$(id -u):$(id -g)" -v $(pwd):/build -e REPO:/build -e DOXYGEN_INCLUDE=/build/doc/Doxyfile.inc -e EXCLUDE_PATTERNS=/build/doc/exclude_patterns.inc -e DOXYGEN_INPUT=ignore ghcr.io/xmos/doc_builder:main + docker run --rm -t -u "$(id -u):$(id -g)" -v $(pwd):/build -e REPO:/build -e DOXYGEN_INCLUDE=/build/doc/Doxyfile.inc -e EXCLUDE_PATTERNS=/build/doc/exclude_patterns.inc -e DOXYGEN_INPUT=ignore ghcr.io/xmos/doc_builder:latest ********************** Adding a New Component diff --git a/doc/contributing.rst b/doc/contributing.rst index 6d9785c21..79f62ecdd 100644 --- a/doc/contributing.rst +++ b/doc/contributing.rst @@ -132,16 +132,7 @@ The following conventions are used when naming CMake targets: - Targets that match ``example_freertos_*`` are FreeRTOS examples - Targets that match ``run_example_*`` are a shortcut recipe to call ``xrun`` with ``xscope`` and the associated firmware - Targets that match ``debug_example_*`` are a shortcut recipe to call ``xgdb`` with ``xscope`` and the associated firmware +- Targets that match ``install_example_*`` are a shortcut recipe to copy the associated firmware to the ``dist`` output directory - Targets that match ``xsim_example_*`` are a shortcut recipe to call ``xsim`` with the associated firmware - Targets that match ``flash_example_*`` are a shortcut recipe to flash required data - Targets that match ``flash_fs_example_*`` are a shortcut recipe to flash required data for applications using a filesystem - -**************** -Development Tips -**************** - -At times submodule repositories will need to be updated. To update all submodules, run the following command - -.. code-block:: console - - git submodule update --init --recursive diff --git a/doc/exclude_patterns.inc b/doc/exclude_patterns.inc index 3796928ac..966de5517 100644 --- a/doc/exclude_patterns.inc +++ b/doc/exclude_patterns.inc @@ -8,7 +8,7 @@ modules/sample_rate_conversion modules/core/modules/legacy_compat modules/core/modules/otpinfo modules/core/modules/random -modules/core/modules/inferencing +modules/core/modules/trycatch modules/io/modules/xud modules/io/doc/substitutions.rst modules/voice/doc/substitutions.rst diff --git a/doc/faq.rst b/doc/faq.rst new file mode 100644 index 000000000..0b90a493b --- /dev/null +++ b/doc/faq.rst @@ -0,0 +1,41 @@ +.. _sdk-faq: + +############################# +Frequently Asked Questions +############################# + +************ +Build Issues +************ + +================= +Submodule updates +================= + +The XCORE SDK uses submodules. If you have cloned the repository and later perform an update, it will sometimes also be necessary to update the submodules. To update all submodules, run the following command + +.. code-block:: console + + git submodule update --init --recursive + +======================== +fatfs_mkimage: not found +======================== + +This issue occurs when the XCORE SDK `fatfs_mkimage` utility cannot be found. The most common cause for these issues are an incomplete installation of the XCORE SDK. + +Ensure that the host applications setup has been completed. Verify that the `fatfs_mkimage` binary is installed to a location on PATH, or that the default application installation folder is added to PATH. See the :ref:`sdk-installation` guide for more information on installing the host applications. + +=============================================== +xcc2clang.exe: error: no such file or directory +=============================================== + +Those strange characters at the beginning of the path are known as a byte-order mark (BOM). CMake adds them to the beginning of the response files it generates during the configure step. Why does it add them? Because the MSVC compiler toolchain requires them. However, some compiler toolchains, like `gcc` and `xcc`, do not ignore the BOM. Why did CMake think the compiler toolchain was MSVC and not the XTC toolchain? Because of a bug in which certain versions of CMake and certain versions of Visual Studio do not play nice together. The good news is that this appears to have been addressed in CMake version 3.22.3. + +Update to CMake version 3.22.2 or newer. + +******** +FreeRTOS +******** + +See the :ref:`freertos-faq` or :ref:`freertos-common_issues` diff --git a/doc/quick_start/index.rst b/doc/quick_start/index.rst index 7467f7249..2d51a8222 100644 --- a/doc/quick_start/index.rst +++ b/doc/quick_start/index.rst @@ -4,11 +4,11 @@ Introduction The XCORE SDK is a collection of C/C++ software libraries designed to simplify and accelerate application development on xcore processors. It 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. -- Libraries core to DSP applications, including vectorized math. These libraries support bare-metal and RTOS application development. +- :ref:`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 :ref:`DSP applications `, including :ref:`vectorized math `. These libraries support bare-metal and RTOS application development. - Voice processing libraries including; adaptive echo cancellation, adaptive gain control, noise suppression, interference cancellation (IC), and voice activity detection. 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. -- Code Examples - Examples showing a variety of xcore features based on bare-metal and FreeRTOS programming. +- Libraries that enable `multi-core FreeRTOS development `__ on xcore including a wide array of :ref:`RTOS drivers and middleware `. +- Code Examples - Examples showing a variety of xcore features based on :ref:`bare-metal ` and :ref:`FreeRTOS ` programming. - Documentation - Getting started guides, references and API guides. The SDK is designed to be used in conjunction with the xcore.ai Explorer board and the Voice Reference evaluation kit. The example applications compile targeting these boards. Further information about the Explorer board, the Voice Reference evaluation kit, and xcore.ai devices is available to on `www.xmos.ai `__. @@ -17,4 +17,4 @@ The SDK is designed to be used in conjunction with the xcore.ai Explorer board a Getting Started *************** -Fast-forward to the :ref:`Tutorials ` for information on installing and using the XCORE SDK. +Fast-forward to the :ref:`Tutorials ` for information on :ref:`system requirements `, :ref:`installing ` and :ref:`using the XCORE SDK `. diff --git a/doc/quick_start/installation.rst b/doc/quick_start/installation.rst index d90866c57..c7d2ddef8 100644 --- a/doc/quick_start/installation.rst +++ b/doc/quick_start/installation.rst @@ -28,12 +28,20 @@ The SDK includes utilities that run on the PC host. Run the following command t $ cd build_host $ sudo make install - This command installs the applications at ``/opt/xmos/SDK//bin/`` directory. You may wish to append this directory to your ``PATH`` variable. + This command installs the applications at `/opt/xmos/SDK//bin/` directory. You may wish to append this directory to your `PATH` variable. .. code-block:: console $ export PATH=$PATH:/opt/xmos/SDK//bin/ + Some host applications require that the location of `xscope_endpoint.so` be added 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 `__. + + Or, you may prefer to set this environment variable manually. + + .. code-block:: console + + $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib + .. tab:: Windows Windows users must run the x86 native tools command prompt from Visual Studio @@ -44,8 +52,9 @@ The SDK includes utilities that run on the PC host. Run the following command t $ cd build_host $ nmake install - This command installs the applications at ``\.xmos\SDK\\bin\`` directory. You may wish to add this directory to your ``PATH`` variable. + This command installs the applications at `\.xmos\SDK\\bin\` directory. You may wish to add this directory to your `PATH` variable. + Some host applications require that the location of `xscope_endpoint.dll` be added 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 `__. Optional Step 3. Install Python and Python Requirements ======================================================= diff --git a/doc/quick_start/system-requirements.rst b/doc/quick_start/system-requirements.rst index ff3ba8d34..e30874283 100644 --- a/doc/quick_start/system-requirements.rst +++ b/doc/quick_start/system-requirements.rst @@ -10,7 +10,9 @@ The XCORE SDK is officially supported on the following platforms. Unofficial sup .. tab:: Windows Windows 10 is supported. - + + A standard C/C++ compiler is required to build applications and libraries on the host PC. Windows users may use `Build Tools for Visual Studio `__ command-line interface. + Windows users can also use the Windows Subsystem for Linux (WSL). See `Windows Subsystem for Linux Installation Guide for Windows 10 `__ to install WSL. The SDK should also work using other Windows GNU development environments like GNU Make, MinGW or Cygwin. @@ -19,7 +21,7 @@ The XCORE SDK is officially supported on the following platforms. Unofficial sup Operating systems macOS 10.5 (Catalina) and newer are supported. Intel processors only. Older operating systems are likely to also work, though they are not supported. - A standard C/C++ compiler is required to build applications and libraries on the host PC. Mac users may use the Xcode command line tools. + A standard C/C++ compiler is required to build applications and libraries on the host PC. Mac users may use the Xcode command-line tools. .. tab:: Linux diff --git a/doc/reference/index.rst b/doc/reference/index.rst index 0d00272fb..9d4ab6caf 100644 --- a/doc/reference/index.rst +++ b/doc/reference/index.rst @@ -8,3 +8,4 @@ References ../../modules/core/index.rst ../../modules/io/index.rst ../../modules/rtos/index.rst + ../../modules/voice/index.rst diff --git a/doc/tutorials/bare-metal/examples/index.rst b/doc/tutorials/bare-metal/examples/index.rst index 54908c3af..5de941ff6 100644 --- a/doc/tutorials/bare-metal/examples/index.rst +++ b/doc/tutorials/bare-metal/examples/index.rst @@ -1,3 +1,5 @@ +.. _sdk-baremetal-code-examples: + ######################## Bare-metal Code Examples ######################## diff --git a/doc/tutorials/build_system/cmakelists.rst b/doc/tutorials/build_system/cmakelists.rst index 8dab7016c..23ad0f6f9 100644 --- a/doc/tutorials/build_system/cmakelists.rst +++ b/doc/tutorials/build_system/cmakelists.rst @@ -1,11 +1,18 @@ ###################### -Example CMakeLists.txt +Example CMakeLists.txt ###################### .. note:: CMake is powerful tool that provides the developer a great deal of flexibility in how their projects are built. As a result, CMakeLists.txt files in the example applications may vary from the examples below. This example can be used as a starting point for your bare-metal application. Or, you may choose to copy a ``CMakeLists.txt`` from one of the applications in the SDK that closely resembles your application. + +This repository supports being added as a CMake subproject. A parent CMake project can use add_subdirectory() to include the xcore_sdk as a subproject. + +.. note:: + + The xcore_sdk subproject should be added before declaring application targets, as some xcore_sdk provided macros may be needed. Additionally, when included as a subproject, xcore_sdk examples targets are not added to the CMake build. + ********** Bare-Metal ********** @@ -133,4 +140,4 @@ Below is an example ``CMakeLists.txt`` that shows both required and conventional ## Optionally create run and debug targets create_run_target(my_app) - create_debug_target(my_app) \ No newline at end of file + create_debug_target(my_app) diff --git a/doc/tutorials/build_system/index.rst b/doc/tutorials/build_system/index.rst index c8574698f..fb931b9cb 100644 --- a/doc/tutorials/build_system/index.rst +++ b/doc/tutorials/build_system/index.rst @@ -6,7 +6,9 @@ Build System ############ -This document describes the `CMake `_-based build system used by the example applications in the XCORE SDK. The build system is designed so a user does not have to be an expert using CMake. However, some familiarity with CMake is helpful. You can familiarize yourself by reading the `Cmake Tutorial `_ or `CMake documentation `_. +This document describes the `CMake `_-based build system used by the example applications in the XCORE SDK. The build system is designed so a user does not have to be an expert using CMake. However, some familiarity with CMake is helpful. You can familiarize yourself by reading the `Cmake Tutorial `_ or `CMake documentation `_. + +Check the :ref:`system requirement prerequisites ` for the supported versions of CMake. ******** Overview diff --git a/doc/tutorials/build_system/target_aliases.rst b/doc/tutorials/build_system/target_aliases.rst index b5e0d7bfa..3dfde8f90 100644 --- a/doc/tutorials/build_system/target_aliases.rst +++ b/doc/tutorials/build_system/target_aliases.rst @@ -176,8 +176,6 @@ If you prefer, you can specify individual software service libraries. - Device control library * - rtos::sw_services::usb_device_control - USB device control library - * - rtos::sw_services::dispatcher - - Dispatcher thread pool library * - rtos::sw_services::wifi_manager - WiFi manager library * - rtos::sw_services::tls_support diff --git a/doc/tutorials/freertos/application_design.rst b/doc/tutorials/freertos/application_design.rst index 59707b9af..778566dca 100644 --- a/doc/tutorials/freertos/application_design.rst +++ b/doc/tutorials/freertos/application_design.rst @@ -62,7 +62,7 @@ Board Support Configurations **************************** xcore leverages its architecture to provide a flexible chip where many typically silicon based peripherals are found in software. This allows a chip to be reconfigured in a way that provides the specific IO required for a given application, thus resulting in a low cost yet incredibly silicon efficient solution. Board support configurations (bsp_configs) are the description for the hardware IO that exists in a given board. The bsp_configs provide the application programmer with an API to initialize and start the hardware configuration, as well as the supported RTOS driver contexts. The programming model in this FreeRTOS architecture is: - * `.xn files `__ provide the mapping of ports, pins, and links + * `.xn files `__ provide the mapping of ports, pins, and links * bsp_configs setup and start hardware IO and provide the application with RTOS driver contexts * applications use the bsp_config init/start code as well as RTOS driver contexts, similar to conventional microcontroller programming models. diff --git a/doc/tutorials/freertos/application_programming.rst b/doc/tutorials/freertos/application_programming.rst index b644e606b..5d18b12aa 100644 --- a/doc/tutorials/freertos/application_programming.rst +++ b/doc/tutorials/freertos/application_programming.rst @@ -83,7 +83,6 @@ Software Services The SDK also includes some higher level RTOS compatible software services, some of which call the aforementioned drivers. These include, but are not necessarily limited to: - DHCP server -- Dispatcher - FAT filesystem - HTTP parser - JSON parser diff --git a/doc/tutorials/freertos/common_issues.rst b/doc/tutorials/freertos/common_issues.rst index ea28da275..b7c97628a 100644 --- a/doc/tutorials/freertos/common_issues.rst +++ b/doc/tutorials/freertos/common_issues.rst @@ -1,7 +1,7 @@ -.. _freertos-common_issues: - .. include:: ../../substitutions.rst +.. _freertos-common_issues: + ###################### FreeRTOS Common Issues ###################### diff --git a/doc/tutorials/freertos/examples/dfu.rst b/doc/tutorials/freertos/examples/dfu.rst new file mode 100644 index 000000000..1535f3263 --- /dev/null +++ b/doc/tutorials/freertos/examples/dfu.rst @@ -0,0 +1 @@ +.. include:: ../../../../examples/freertos/dfu/README.rst diff --git a/doc/tutorials/freertos/examples/dispatcher.rst b/doc/tutorials/freertos/examples/dispatcher.rst deleted file mode 100644 index 23311c13b..000000000 --- a/doc/tutorials/freertos/examples/dispatcher.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../../../examples/freertos/dispatcher/README.rst diff --git a/doc/tutorials/freertos/examples/images/xscope_fileio_functional_diagram.png b/doc/tutorials/freertos/examples/images/xscope_fileio_functional_diagram.png new file mode 100644 index 000000000..6635c3d19 Binary files /dev/null and b/doc/tutorials/freertos/examples/images/xscope_fileio_functional_diagram.png differ diff --git a/doc/tutorials/freertos/examples/index.rst b/doc/tutorials/freertos/examples/index.rst index e041ab0a4..c10d53065 100644 --- a/doc/tutorials/freertos/examples/index.rst +++ b/doc/tutorials/freertos/examples/index.rst @@ -11,7 +11,9 @@ Several FreeRTOS code examples are included to illustrate the fundamental tool f :includehidden: explorer_board.rst + tracealyzer.rst + xscope_fileio.rst device_control.rst - dispatcher.rst l2_cache.rst iot.rst + xlink.rst diff --git a/doc/tutorials/freertos/examples/tracealyzer.rst b/doc/tutorials/freertos/examples/tracealyzer.rst new file mode 100644 index 000000000..ba707e611 --- /dev/null +++ b/doc/tutorials/freertos/examples/tracealyzer.rst @@ -0,0 +1 @@ +.. include:: ../../../../examples/freertos/tracealyzer/README.rst diff --git a/doc/tutorials/freertos/examples/xlink.rst b/doc/tutorials/freertos/examples/xlink.rst new file mode 100644 index 000000000..b1a352da8 --- /dev/null +++ b/doc/tutorials/freertos/examples/xlink.rst @@ -0,0 +1 @@ +.. include:: ../../../../examples/freertos/xlink/README.rst diff --git a/doc/tutorials/freertos/examples/xscope_fileio.rst b/doc/tutorials/freertos/examples/xscope_fileio.rst new file mode 100644 index 000000000..2a785f249 --- /dev/null +++ b/doc/tutorials/freertos/examples/xscope_fileio.rst @@ -0,0 +1 @@ +.. include:: ../../../../examples/freertos/xscope_fileio/README.rst diff --git a/doc/tutorials/freertos/faq.rst b/doc/tutorials/freertos/faq.rst index 7c939e54e..7d2d2febd 100644 --- a/doc/tutorials/freertos/faq.rst +++ b/doc/tutorials/freertos/faq.rst @@ -1,7 +1,7 @@ -.. _freertos-faq: - .. include:: ../../substitutions.rst +.. _freertos-faq: + ############# FreeRTOS FAQs ############# @@ -25,7 +25,7 @@ FreeRTOS FAQs EXAMPLE_TASK_PRIORITY, NULL); - If function pointers are used within a thread, then the application programmer must annotate the code with the appropriate function pointer group attribute. For recursive functions, the only option is to specify the stack manually. See `Appendix A - Guiding Stack Size Calculation `_ in the XTC Tools documentation for more information. + If function pointers are used within a thread, then the application programmer must annotate the code with the appropriate function pointer group attribute. For recursive functions, the only option is to specify the stack manually. See `Appendix A - Guiding Stack Size Calculation `_ in the XTC Tools documentation for more information. 3. Can I use xcore resources like channels, timers and hw_locks? diff --git a/doc/tutorials/platform.rst b/doc/tutorials/platform.rst index d380291a5..519dc6d14 100644 --- a/doc/tutorials/platform.rst +++ b/doc/tutorials/platform.rst @@ -6,10 +6,10 @@ Platform Architecture & Hardware Guide ***************************** -See the `Architecture & Hardware Guide `_ in the XTC Tools documentation for an introduction to the xcore platform architecture and hardware. +See the `Architecture & Hardware Guide `_ in the XTC Tools documentation for an introduction to the xcore platform architecture and hardware. ***************** Programming Guide ***************** -See the `Programming Guide `_ in the XTC Tools documentation for an introduction to xcore platform programming. +See the `Programming Guide `_ in the XTC Tools documentation for an introduction to xcore platform programming. diff --git a/examples/bare-metal/explorer_board/explorer_board.cmake b/examples/bare-metal/explorer_board/explorer_board.cmake index 32d00b9df..d9bab38cc 100644 --- a/examples/bare-metal/explorer_board/explorer_board.cmake +++ b/examples/bare-metal/explorer_board/explorer_board.cmake @@ -37,6 +37,7 @@ set(APP_COMPILE_DEFINITIONS MIC_ARRAY_CONFIG_PORT_MCLK=PORT_MCLK_IN MIC_ARRAY_CONFIG_PORT_PDM_CLK=PORT_PDM_CLK MIC_ARRAY_CONFIG_PORT_PDM_DATA=PORT_PDM_DATA + XUD_CORE_CLOCK=600 ) set(APP_LINK_OPTIONS @@ -66,3 +67,4 @@ mic_array_vanilla_add( example_bare_metal_explorer_board create_run_target(example_bare_metal_explorer_board) create_debug_target(example_bare_metal_explorer_board) create_flash_app_target(example_bare_metal_explorer_board) +create_install_target(example_bare_metal_explorer_board) diff --git a/examples/bare-metal/explorer_board/src/audio_pipeline/audio_pipeline.c b/examples/bare-metal/explorer_board/src/audio_pipeline/audio_pipeline.c index fc7c62802..7265ca9b1 100644 --- a/examples/bare-metal/explorer_board/src/audio_pipeline/audio_pipeline.c +++ b/examples/bare-metal/explorer_board/src/audio_pipeline/audio_pipeline.c @@ -10,7 +10,7 @@ /* SDK headers */ #include "xcore_utils.h" #include "mic_array.h" -#include "bfp_math.h" +#include "xmath/xmath.h" /* App headers */ #include "app_conf.h" @@ -69,7 +69,7 @@ void ap_stage_b(chanend_t c_input, chanend_t c_output, chanend_t c_from_gpio) { // update the gain float power = (float)gain_db / 20.0; float gain_fl = powf(10.0, power); - float_s32_t gain = float_to_float_s32(gain_fl); + float_s32_t gain = f32_to_float_s32(gain_fl); // scale both channels bfp_s32_scale(&ch0, &ch0, gain); bfp_s32_scale(&ch1, &ch1, gain); @@ -96,7 +96,7 @@ void ap_stage_b(chanend_t c_input, chanend_t c_output, chanend_t c_from_gpio) { gain_db = (gain_db <= appconfAUDIO_PIPELINE_MIN_GAIN) ? gain_db : gain_db - appconfAUDIO_PIPELINE_GAIN_STEP; break; } - debug_printf("Gain set to %f\n", gain_db); + debug_printf("Gain set to %d\n", gain_db); } continue; } diff --git a/examples/examples.cmake b/examples/examples.cmake index a7155e7fc..032246edc 100644 --- a/examples/examples.cmake +++ b/examples/examples.cmake @@ -2,15 +2,32 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL XCORE_XS3A) ## Bare metal examples include(${CMAKE_CURRENT_LIST_DIR}/bare-metal/explorer_board/explorer_board.cmake) - # + ## FreeRTOS examples + include(${CMAKE_CURRENT_LIST_DIR}/freertos/dfu/dfu.cmake) include(${CMAKE_CURRENT_LIST_DIR}/freertos/device_control/device_control.cmake) - include(${CMAKE_CURRENT_LIST_DIR}/freertos/dispatcher/dispatcher.cmake) include(${CMAKE_CURRENT_LIST_DIR}/freertos/explorer_board/explorer_board.cmake) include(${CMAKE_CURRENT_LIST_DIR}/freertos/getting_started/getting_started.cmake) include(${CMAKE_CURRENT_LIST_DIR}/freertos/iot/iot.cmake) include(${CMAKE_CURRENT_LIST_DIR}/freertos/l2_cache/l2_cache.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/freertos/tracealyzer/tracealyzer.cmake) include(${CMAKE_CURRENT_LIST_DIR}/freertos/usb/usb.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/freertos/xlink/xlink.cmake) + include(${CMAKE_CURRENT_LIST_DIR}/freertos/xscope_fileio/xscope_fileio.cmake) else() + # Get the "version" value from the JSON element + file(READ settings.json JSON_STRING) + string(JSON SDK_VERSION GET ${JSON_STRING} ${IDX} version) + + # Determine OS, set up install dir + if(${CMAKE_SYSTEM_NAME} STREQUAL Windows) + set(HOST_INSTALL_DIR "$ENV{USERPROFILE}\\.xmos\\SDK\\${SDK_VERSION}\\bin") + else() + set(HOST_INSTALL_DIR "/opt/xmos/SDK/${SDK_VERSION}/bin") + endif() + add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/freertos/device_control/host) + add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/freertos/tracealyzer/host) + add_subdirectory(modules/xscope_fileio/xscope_fileio/host) + install(TARGETS xscope_host_endpoint DESTINATION ${HOST_INSTALL_DIR}) endif() diff --git a/examples/freertos/device_control/device_control.cmake b/examples/freertos/device_control/device_control.cmake index 2f677a2b8..c40b193f6 100644 --- a/examples/freertos/device_control/device_control.cmake +++ b/examples/freertos/device_control/device_control.cmake @@ -78,3 +78,4 @@ merge_binaries(example_freertos_device_control tile0_example_freertos_device_con create_run_target(example_freertos_device_control) create_debug_target(example_freertos_device_control) create_flash_app_target(example_freertos_device_control) +create_install_target(example_freertos_device_control) diff --git a/examples/freertos/dfu/README.rst b/examples/freertos/dfu/README.rst new file mode 100644 index 000000000..a498269c0 --- /dev/null +++ b/examples/freertos/dfu/README.rst @@ -0,0 +1,249 @@ +############## +DFU +############## + +This example application demonstrates a method to add DFU to a FreeRTOS application on XCORE. + +********************** +Preparing the host +********************** + +This application supports any host host application that is capable of USB DFU Class V1.1. + +The application was verified using dfu-util. + +Installation instructions for respective operating system can be found `here `__ + +If on Linux the user may need to add the USB device to their udev rules. This example defaults to Vendor ID 0xCAFE with Product ID 0x4000. + +If on Windows the user may need to use a tool such as Zadig to install USB drivers. + +********************* +Building the firmware +********************* + +Run the following commands in the xcore_sdk root folder to build the firmware: + +.. tab:: Linux and Mac + + .. code-block:: console + + cmake -B build -DCMAKE_TOOLCHAIN_FILE=xmos_cmake_toolchain/xs3a.cmake + cd build + make example_freertos_dfu_v1 + make example_freertos_dfu_v2 + +.. tab:: Windows + + .. code-block:: console + + cmake -G "NMake Makefiles" -B build -DCMAKE_TOOLCHAIN_FILE=xmos_cmake_toolchain/xs3a.cmake + cd build + nmake example_freertos_dfu_v1 + nmake example_freertos_dfu_v2 + +********************** +Preparing the hardware +********************** + +It is recommended to begin from an erased flash. To erase flash run: + +.. tab:: Linux and Mac + + .. code-block:: console + + make erase_all_example_freertos_dfu_v1 + +.. tab:: Windows + + .. code-block:: console + + nmake erase_all_example_freertos_dfu_v1 + +This target will use `xflash` to erase the flash of the device specified by the provided target XN file. + +After building the firmware and erasing the flash, the factory image must be flashed. From the xcore_sdk build folder run: + +.. tab:: Linux and Mac + + .. code-block:: console + + make flash_app_example_freertos_dfu_v1 + +.. tab:: Windows + + .. code-block:: console + + nmake flash_app_example_freertos_dfu_v1 + +This target will use `xflash` to flash the application as a factory image with a boot partition size specified in dfu.cmake. + +The board may then be power cycled and will boot up the application. + +.. tab:: Linux and Mac + + .. code-block:: console + + make create_upgrade_img_example_freertos_dfu_v2 + +.. tab:: Windows + + .. code-block:: console + + nmake create_upgrade_img_example_freertos_dfu_v2 + +This target will use `xflash` to create an upgrade image for the specified target. + +******************** +Running the firmware +******************** + +After flashed, the factory image will run by default. The user may opt to manually run via xrun to see debug messages. + +From the xcore_sdk build folder run: + +.. tab:: Linux and Mac + + .. code-block:: console + + make run_example_freertos_dfu_v1 + +.. tab:: Windows + + .. code-block:: console + + nmake run_example_freertos_dfu_v1 + +******************** +Upgrading the firmware via DFU +******************** + +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. + +MacOS users may need to sudo the following commands. + +To verify the device is running run: + +.. code-block:: console + + dfu-util -l + +The output of this command will very based on which image is running. +For example_freertos_dfu_v1, the output should contain: + +.. code-block:: console + + Found DFU: [cafe:4000] ver=0100, devnum=53, cfg=1, intf=0, path="3-4.1", alt=2, name="DFU dev DATAPARTITION v1", serial="123456" + Found DFU: [cafe:4000] ver=0100, devnum=53, cfg=1, intf=0, path="3-4.1", alt=1, name="DFU dev UPGRADE v1", serial="123456" + Found DFU: [cafe:4000] ver=0100, devnum=53, cfg=1, intf=0, path="3-4.1", alt=0, name="DFU dev FACTORY v1", serial="123456" + +For example_freertos_dfu_v2, the output should contain: + +.. code-block:: console + + Found DFU: [cafe:4000] ver=0100, devnum=53, cfg=1, intf=0, path="3-4.1", alt=2, name="DFU dev DATAPARTITION v2", serial="123456" + Found DFU: [cafe:4000] ver=0100, devnum=53, cfg=1, intf=0, path="3-4.1", alt=1, name="DFU dev UPGRADE v2", serial="123456" + Found DFU: [cafe:4000] ver=0100, devnum=53, cfg=1, intf=0, path="3-4.1", alt=0, name="DFU dev FACTORY v2", serial="123456" + +The factory image can be read back by running: + +.. code-block:: console + + dfu-util -e -d 4000 -a 0 -U readback_factory_img.bin + +From the xcore_sdk build folder, the upgrade image can be written by running: + +.. code-block:: console + + dfu-util -e -d 4000 -a 1 -D example_freertos_dfu_v2_upgrade.bin + +After updating the upgrade image it may be necessary to unplug the USB device to initiate a host re-enumeration. + +The upgrade image can be read back by running: + +.. code-block:: console + + dfu-util -e -d 4000 -a 1 -U readback_upgrade_img.bin + +The data partition image can be read back by running: + +.. code-block:: console + + dfu-util -e -d 4000 -a 2 -U readback_data_partition_img.bin + +The data partition image can be written by running: + +.. code-block:: console + + dfu-util -e -d 4000 -a 2 -D readback_data_partition_img.bin + +If running the application with the run_example_freertos_dfu_v1 target, information is printed to verify behavior. + +Initially, the debug prints will contain: + +.. code-block:: console + + DFU Image Info + Factory: + Addr:0x1C70 + Size:103108 + Version:0 + Upgrade: + Addr:0x1B000 + Size:0 + Version:0 + Data Partition + Addr:0x100000 + First word at data partition start is: 0xFFFFFFFF + +After writing an upgrade image the debug prints will contain: + +.. code-block:: console + + DFU Image Info + Factory: + Addr:0x1C70 + Size:103108 + Version:0 + Upgrade: + Addr:0x1B000 + Size:103108 + Version:0 + Data Partition + Addr:0x100000 + First word at data partition start is: 0xFFFFFFFF + +The debug prints include the value of the first word at the start of the data partition. Writing a text file containing "XMOS" will result in: + +.. code-block:: console + + DFU Image Info + Factory: + Addr:0x1C70 + Size:103108 + Version:0 + Upgrade: + Addr:0x1B000 + Size:103108 + Version:0 + Data Partition + Addr:0x100000 + First word at data partition start is: 0x534F4D58 + +******************************** +Debugging the firmware with xgdb +******************************** + +From the xcore_sdk build folder run: + +.. tab:: Linux and Mac + + .. code-block:: console + + make debug_example_freertos_dfu_v1 + +.. tab:: Windows + + .. code-block:: console + + nmake debug_example_freertos_dfu_v1 diff --git a/examples/freertos/dfu/XCORE-AI-EXPLORER.xn b/examples/freertos/dfu/XCORE-AI-EXPLORER.xn new file mode 100644 index 000000000..4dde19f84 --- /dev/null +++ b/examples/freertos/dfu/XCORE-AI-EXPLORER.xn @@ -0,0 +1,109 @@ + + + Board + xcore.ai Explorer Kit + + + tileref tile[2] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/freertos/dfu/bsp_config/CMakeLists.txt b/examples/freertos/dfu/bsp_config/CMakeLists.txt new file mode 100644 index 000000000..e7321512e --- /dev/null +++ b/examples/freertos/dfu/bsp_config/CMakeLists.txt @@ -0,0 +1,35 @@ +## Create Explorer Board 2V0 target +add_library(example_freertos_dfu_board_support_config_xcore_ai_explorer_2V0 INTERFACE) +target_sources(example_freertos_dfu_board_support_config_xcore_ai_explorer_2V0 + INTERFACE + XCORE-AI-EXPLORER_2V0/platform/driver_instances.c + XCORE-AI-EXPLORER_2V0/platform/platform_init.c + XCORE-AI-EXPLORER_2V0/platform/platform_start.c +) +target_include_directories(example_freertos_dfu_board_support_config_xcore_ai_explorer_2V0 + INTERFACE + XCORE-AI-EXPLORER_2V0 +) +target_link_libraries(example_freertos_dfu_board_support_config_xcore_ai_explorer_2V0 + INTERFACE + core::general + rtos::freertos + rtos::drivers::general + rtos::drivers::usb + rtos::drivers::dfu_image + rtos::sw_services::usb + +) +target_compile_definitions(example_freertos_dfu_board_support_config_xcore_ai_explorer_2V0 + INTERFACE + XCOREAI_EXPLORER=1 + PLATFORM_SUPPORTS_TILE_0=1 + PLATFORM_SUPPORTS_TILE_1=1 + PLATFORM_SUPPORTS_TILE_2=0 + PLATFORM_SUPPORTS_TILE_3=0 + USB_TILE_NO=0 + USB_TILE=tile[USB_TILE_NO] +) + +## Create an alias +add_library(example::freertos::dfu::bsp_config::xcore_ai_explorer ALIAS example_freertos_dfu_board_support_config_xcore_ai_explorer_2V0) diff --git a/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.c b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.c new file mode 100644 index 000000000..d5344d6e2 --- /dev/null +++ b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.c @@ -0,0 +1,34 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#include "platform/driver_instances.h" + +static rtos_intertile_t intertile_ctx_s; +rtos_intertile_t *intertile_ctx = &intertile_ctx_s; + +static rtos_qspi_flash_t qspi_flash_ctx_s; +rtos_qspi_flash_t *qspi_flash_ctx = &qspi_flash_ctx_s; + +static rtos_spi_master_t spi_master_ctx_s; +rtos_spi_master_t *spi_master_ctx = &spi_master_ctx_s; + +static rtos_spi_master_device_t wifi_device_ctx_s; +rtos_spi_master_device_t *wifi_device_ctx = &wifi_device_ctx_s; + +static rtos_gpio_t gpio_ctx_t0_s; +rtos_gpio_t *gpio_ctx_t0 = &gpio_ctx_t0_s; + +static rtos_gpio_t gpio_ctx_t1_s; +rtos_gpio_t *gpio_ctx_t1 = &gpio_ctx_t1_s; + +static rtos_i2c_master_t i2c_master_ctx_s; +rtos_i2c_master_t *i2c_master_ctx = &i2c_master_ctx_s; + +static rtos_uart_tx_t uart_tx_ctx_s; +rtos_uart_tx_t *uart_tx_ctx = &uart_tx_ctx_s; + +static rtos_uart_rx_t uart_rx_ctx_s; +rtos_uart_rx_t *uart_rx_ctx = &uart_rx_ctx_s; + +static rtos_dfu_image_t dfu_image_ctx_s; +rtos_dfu_image_t *dfu_image_ctx = &dfu_image_ctx_s; diff --git a/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.h b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.h new file mode 100644 index 000000000..ee4a4d65a --- /dev/null +++ b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.h @@ -0,0 +1,46 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#ifndef DRIVER_INSTANCES_H_ +#define DRIVER_INSTANCES_H_ + +#include "rtos_intertile.h" +#include "rtos_i2c_master.h" +#include "rtos_spi_master.h" +#include "rtos_qspi_flash.h" +#include "rtos_dfu_image.h" +#include "rtos_gpio.h" +#include "rtos_uart_tx.h" +#include "rtos_uart_rx.h" +#include "usb_support.h" + +#define FLASH_TILE_NO 0 +#define I2C_TILE_NO 0 +#define UART_TILE_NO 1 + +/** TILE 0 Clock Blocks */ +#define FLASH_CLKBLK XS1_CLKBLK_1 +// #define UNUSED_CLKBLK XS1_CLKBLK_2 +#define SPI_CLKBLK XS1_CLKBLK_3 +#define XUD_CLKBLK_1 XS1_CLKBLK_4 /* Reserved for lib_xud */ +#define XUD_CLKBLK_2 XS1_CLKBLK_5 /* Reserved for lib_xud */ + +/** TILE 1 Clock Blocks */ +// #define UNUSED_CLKBLK XS1_CLKBLK_1 +// #define UNUSED_CLKBLK XS1_CLKBLK_2 +// #define UNUSED_CLKBLK XS1_CLKBLK_3 +// #define UNUSED_CLKBLK XS1_CLKBLK_4 +// #define UNUSED_CLKBLK XS1_CLKBLK_5 + +extern rtos_intertile_t *intertile_ctx; +extern rtos_qspi_flash_t *qspi_flash_ctx; +extern rtos_spi_master_t *spi_master_ctx; +extern rtos_spi_master_device_t *wifi_device_ctx; +extern rtos_gpio_t *gpio_ctx_t0; +extern rtos_gpio_t *gpio_ctx_t1; +extern rtos_i2c_master_t *i2c_master_ctx; +extern rtos_uart_tx_t *uart_tx_ctx; +extern rtos_uart_rx_t *uart_rx_ctx; +extern rtos_dfu_image_t *dfu_image_ctx; + +#endif /* DRIVER_INSTANCES_H_ */ diff --git a/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_conf.h b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_conf.h new file mode 100644 index 000000000..80d2d56aa --- /dev/null +++ b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_conf.h @@ -0,0 +1,135 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#ifndef PLATFORM_CONF_H_ +#define PLATFORM_CONF_H_ + +/* + * This file contains defaults to build a basic project targetting the + * XCORE-AI-EXPLORER board. Users may create their own app_conf.h to override + * any default settings. + * + * For a different soft tapeout design, it is recommended to create an entirely + * different board support package. + */ + +#if __has_include("app_conf.h") +#include "app_conf.h" +#endif /* __has_include("app_conf.h") */ + +/*****************************************/ +/* Intertile Communication Configuration */ +/*****************************************/ +#ifndef appconfI2C_MASTER_RPC_PORT +#define appconfI2C_MASTER_RPC_PORT 10 +#endif /* appconfI2C_MASTER_RPC_PORT */ + +#ifndef appconfI2C_MASTER_RPC_PRIORITY +#define appconfI2C_MASTER_RPC_PRIORITY (configMAX_PRIORITIES/2) +#endif /* appconfI2C_MASTER_RPC_PRIORITY */ + +#ifndef appconfGPIO_T0_RPC_PORT +#define appconfGPIO_T0_RPC_PORT 11 +#endif /* appconfGPIO_T0_RPC_PORT */ + +#ifndef appconfGPIO_T1_RPC_PORT +#define appconfGPIO_T1_RPC_PORT 12 +#endif /* appconfGPIO_T1_RPC_PORT */ + +#ifndef appconfGPIO_RPC_PRIORITY +#define appconfGPIO_RPC_PRIORITY (configMAX_PRIORITIES/2) +#endif /* appconfGPIO_RPC_PRIORITY */ + +/*****************************************/ +/* I/O and interrupt cores for Tile 0 */ +/*****************************************/ +#ifndef appconfI2C_IO_CORE +#define appconfI2C_IO_CORE 2 /* 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 */ + +/*****************************************/ +/* I/O and interrupt cores for Tile 1 */ +/*****************************************/ +#ifndef appconfUART_RX_IO_CORE +#define appconfUART_RX_IO_CORE 3 /* Must be kept off core 0 with the RTOS tick ISR */ +#endif /* appconfUART_RX_IO_CORE */ + +#ifndef appconfUART_RX_INTERRUPT_CORE +#define appconfUART_RX_INTERRUPT_CORE 4 /* Must be kept off I/O cores. Best kept off core 0 with the tick ISR. */ +#endif /* appconfUART_RX_INTERRUPT_CORE */ + +/*****************************************/ +/* I/O Settings */ +/*****************************************/ +#ifndef appconfUART_BAUD_RATE +#define appconfUART_BAUD_RATE 115200 +#endif /* appconfUART_BAUD_RATE */ + +/*****************************************/ +/* I/O Task Priorities */ +/*****************************************/ +#ifndef appconfSPI_MASTER_TASK_PRIORITY +#define appconfSPI_MASTER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#endif /* appconfSPI_MASTER_TASK_PRIORITY */ + +#ifndef appconfQSPI_FLASH_TASK_PRIORITY +#define appconfQSPI_FLASH_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#endif /* appconfQSPI_FLASH_TASK_PRIORITY */ + +/*****************************************/ +/* DFU Settings */ +/*****************************************/ +#define FL_QUADDEVICE_AT25FF321A \ +{ \ + 0, /* UNKNOWN */ \ + 256, /* page size */ \ + 16384, /* num pages */ \ + 3, /* address size */ \ + 3, /* log2 clock divider */ \ + 0x9F, /* QSPI_RDID */ \ + 0, /* id dummy bytes */ \ + 3, /* id size in bytes */ \ + 0x1F4708, /* device id */ \ + 0x20, /* QSPI_SE */ \ + 4096, /* Sector erase is always 4KB */ \ + 0x06, /* QSPI_WREN */ \ + 0x04, /* QSPI_WRDI */ \ + PROT_TYPE_SR, /* Protection via SR */ \ + {{0x3C,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */ \ + 0x02, /* QSPI_PP */ \ + 0xEB, /* QSPI_READ_FAST */ \ + 1, /* 1 read dummy byte */ \ + SECTOR_LAYOUT_REGULAR, /* mad sectors */ \ + {4096,{0,{0}}}, /* regular sector sizes */ \ + 0x05, /* QSPI_RDSR */ \ + 0x01, /* QSPI_WRSR */ \ + 0x01, /* QSPI_WIP_BIT_MASK */ \ +} + +#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.3.0 + * By default FL_QUADDEVICE_AT25FF321A 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 + * default spec + */ +#define BOARD_QSPI_SPEC FL_QUADDEVICE_DEFAULT +#else +#define BOARD_QSPI_SPEC FL_QUADDEVICE_AT25FF321A +#endif +#else +#define BOARD_QSPI_SPEC FL_QUADDEVICE_AT25FF321A +#endif /* __XMOS_XTC_VERSION_MAJOR__ */ +#endif /* BOARD_QSPI_SPEC */ + +#endif /* PLATFORM_CONF_H_ */ diff --git a/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.c b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.c new file mode 100644 index 000000000..b9e722960 --- /dev/null +++ b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.c @@ -0,0 +1,213 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#include +#include + +#include "platform_conf.h" +#include "platform/driver_instances.h" +#include +#include + +static void flash_init(void) +{ +#if ON_TILE(FLASH_TILE_NO) + fl_QuadDeviceSpec qspi_spec = BOARD_QSPI_SPEC; + fl_QSPIPorts qspi_ports = { + .qspiCS = PORT_SQI_CS, + .qspiSCLK = PORT_SQI_SCLK, + .qspiSIO = PORT_SQI_SIO, + .qspiClkblk = FLASH_CLKBLK, + }; + + rtos_dfu_image_init( + dfu_image_ctx, + &qspi_ports, + &qspi_spec, + 1); + + qspi_flash_ctx->ctx.sfdp_skip = true; + qspi_flash_ctx->ctx.sfdp_supported = false; + qspi_flash_ctx->ctx.page_size_bytes = 256; + qspi_flash_ctx->ctx.page_count = 16384; + qspi_flash_ctx->ctx.flash_size_kbytes = 4096; + qspi_flash_ctx->ctx.address_bytes = 3; + qspi_flash_ctx->ctx.erase_info[0].size_log2 = 12; + qspi_flash_ctx->ctx.erase_info[0].cmd = 0xEEFEEEEE; + qspi_flash_ctx->ctx.erase_info[1].size_log2 = 15; + qspi_flash_ctx->ctx.erase_info[1].cmd = 0xEFEFEEFE; + qspi_flash_ctx->ctx.erase_info[2].size_log2 = 16; + qspi_flash_ctx->ctx.erase_info[2].cmd = 0xFFEFFEEE; + qspi_flash_ctx->ctx.erase_info[3].size_log2 = 0; + qspi_flash_ctx->ctx.erase_info[3].cmd = 0; + qspi_flash_ctx->ctx.busy_poll_cmd = 0xEEEEEFEF; + qspi_flash_ctx->ctx.busy_poll_bit = 0; + qspi_flash_ctx->ctx.busy_poll_ready_value = 0; + qspi_flash_ctx->ctx.qe_reg = 2; + qspi_flash_ctx->ctx.qe_bit = 1; + qspi_flash_ctx->ctx.sr2_read_cmd = 0xEEFFEFEF; + qspi_flash_ctx->ctx.sr2_write_cmd = 0xEEEEEEEE; + + rtos_qspi_flash_init( + qspi_flash_ctx, + FLASH_CLKBLK, + PORT_SQI_CS, + PORT_SQI_SCLK, + PORT_SQI_SIO, + + /** Derive QSPI clock from the 600 MHz xcore clock **/ + qspi_io_source_clock_xcore, + + /** Full speed clock configuration **/ + 5, // 600 MHz / (2*5) -> 60 MHz, + 1, + qspi_io_sample_edge_rising, + 0, + + /** SPI read clock configuration **/ + 12, // 600 MHz / (2*12) -> 25 MHz + 0, + qspi_io_sample_edge_falling, + 0, + + qspi_flash_page_program_1_1_4); +#endif +} + +static void gpio_init(void) +{ + static rtos_driver_rpc_t gpio_rpc_config_t0; + static rtos_driver_rpc_t gpio_rpc_config_t1; + rtos_intertile_t *client_intertile_ctx[1] = {intertile_ctx}; + +#if ON_TILE(0) + rtos_gpio_init(gpio_ctx_t0); + + rtos_gpio_rpc_host_init( + gpio_ctx_t0, + &gpio_rpc_config_t0, + client_intertile_ctx, + 1); + + rtos_gpio_rpc_client_init( + gpio_ctx_t1, + &gpio_rpc_config_t1, + intertile_ctx); +#endif + +#if ON_TILE(1) + rtos_gpio_init(gpio_ctx_t1); + + rtos_gpio_rpc_client_init( + gpio_ctx_t0, + &gpio_rpc_config_t0, + intertile_ctx); + + rtos_gpio_rpc_host_init( + gpio_ctx_t1, + &gpio_rpc_config_t1, + client_intertile_ctx, + 1); +#endif +} + +static void i2c_init(void) +{ + static rtos_driver_rpc_t i2c_rpc_config; + +#if ON_TILE(I2C_TILE_NO) + rtos_intertile_t *client_intertile_ctx[1] = {intertile_ctx}; + rtos_i2c_master_init( + i2c_master_ctx, + PORT_I2C_SCL, 0, 0, + PORT_I2C_SDA, 0, 0, + 0, + 100); + + rtos_i2c_master_rpc_host_init( + i2c_master_ctx, + &i2c_rpc_config, + client_intertile_ctx, + 1); +#else + rtos_i2c_master_rpc_client_init( + i2c_master_ctx, + &i2c_rpc_config, + intertile_ctx); +#endif +} + +static void spi_init(void) +{ +#if ON_TILE(0) + rtos_spi_master_init( + spi_master_ctx, + SPI_CLKBLK, + WIFI_CS_N, + WIFI_CLK, + WIFI_MOSI, + WIFI_MISO); + + rtos_spi_master_device_init( + wifi_device_ctx, + spi_master_ctx, + 1, /* WiFi CS pin is on bit 1 of the CS port */ + SPI_MODE_0, + spi_master_source_clock_ref, + 0, /* 50 MHz */ + spi_master_sample_delay_2, /* what should this be? 2? 3? 4? */ + 0, /* should this be > 0 if the above is 3-4 ? */ + 1, + 0, + 0); +#endif +} + + +static void uart_init(void) +{ +#if ON_TILE(UART_TILE_NO) + hwtimer_t tmr_rx = hwtimer_alloc(); + + rtos_uart_rx_init( + uart_rx_ctx, + (1 << appconfUART_RX_IO_CORE), + XS1_PORT_1M, //X1D36 + appconfUART_BAUD_RATE, + 8, + UART_PARITY_NONE, + 1, + tmr_rx); + + + hwtimer_t tmr_tx = hwtimer_alloc(); + + rtos_uart_tx_init( + uart_tx_ctx, + XS1_PORT_1P, //X1D39 + appconfUART_BAUD_RATE, + 8, + UART_PARITY_NONE, + 1, + tmr_tx); +#endif +} + +void usb_init(void) +{ +#if ON_TILE(USB_TILE_NO) + usb_manager_init(); +#endif +} + +void platform_init(chanend_t other_tile_c) +{ + rtos_intertile_init(intertile_ctx, other_tile_c); + + flash_init(); + gpio_init(); + spi_init(); + i2c_init(); + uart_init(); + usb_init(); +} diff --git a/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.h b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.h new file mode 100644 index 000000000..bae19eb7a --- /dev/null +++ b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.h @@ -0,0 +1,12 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#ifndef PLATFORM_INIT_H_ +#define PLATFORM_INIT_H_ + +#include + +void platform_init(chanend_t other_tile_c); +void platform_start(void); + +#endif /* PLATFORM_INIT_H_ */ diff --git a/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_start.c b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_start.c new file mode 100644 index 000000000..caa1e6613 --- /dev/null +++ b/examples/freertos/dfu/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_start.c @@ -0,0 +1,60 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#include + +#include "platform_conf.h" +#include "platform/driver_instances.h" + +static void gpio_start(void) +{ + rtos_gpio_rpc_config(gpio_ctx_t0, appconfGPIO_T0_RPC_PORT, appconfGPIO_RPC_PRIORITY); + rtos_gpio_rpc_config(gpio_ctx_t1, appconfGPIO_T1_RPC_PORT, appconfGPIO_RPC_PRIORITY); + +#if ON_TILE(0) + rtos_gpio_start(gpio_ctx_t0); +#endif +#if ON_TILE(1) + rtos_gpio_start(gpio_ctx_t1); +#endif +} + +static void spi_start(void) +{ +#if ON_TILE(0) + rtos_spi_master_start(spi_master_ctx, appconfSPI_MASTER_TASK_PRIORITY); +#endif +} + +static void i2c_start(void) +{ + 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 +} + +static void flash_start(void) +{ +#if ON_TILE(0) + rtos_qspi_flash_start(qspi_flash_ctx, appconfQSPI_FLASH_TASK_PRIORITY); +#endif +} + +static void usb_start(void) +{ +#if ON_TILE(USB_TILE_NO) + usb_manager_start(appconfUSB_MANAGER_TASK_PRIORITY); +#endif +} + +void platform_start(void) +{ + rtos_intertile_start(intertile_ctx); + + gpio_start(); + spi_start(); + flash_start(); + i2c_start(); + usb_start(); +} diff --git a/examples/freertos/dfu/dfu.cmake b/examples/freertos/dfu/dfu.cmake new file mode 100644 index 000000000..d63611f4b --- /dev/null +++ b/examples/freertos/dfu/dfu.cmake @@ -0,0 +1,119 @@ +#********************** +# Gather Sources +#********************** +file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c) +set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src) + +#********************** +# Import example specific bsp_config +#********************** +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/bsp_config) + +#********************** +# Flags +#********************** +set(APP_COMPILER_FLAGS + -Os + -g + -report + -fxscope + -mcmodel=large + -Wno-xcore-fptrgroup + ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn +) +set(APP_COMPILE_DEFINITIONS + DEBUG_PRINT_ENABLE=1 + PLATFORM_USES_TILE_0=1 + PLATFORM_USES_TILE_1=1 + + XUD_CORE_CLOCK=600 +) + +set(APP_LINK_OPTIONS + -fxscope + -report + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn + ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope +) + +set(APP_LINK_LIBRARIES + example::freertos::dfu::bsp_config::xcore_ai_explorer +) + +#********************** +# Tile Targets +#********************** +set(TARGET_NAME tile0_example_freertos_dfu_v1) +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 ${APP_COMPILE_DEFINITIONS} THIS_XCORE_TILE=0 VERSION=1) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +set(TARGET_NAME tile1_example_freertos_dfu_v1) +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 ${APP_COMPILE_DEFINITIONS} THIS_XCORE_TILE=1 VERSION=1) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +set(TARGET_NAME tile0_example_freertos_dfu_v2) +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 ${APP_COMPILE_DEFINITIONS} THIS_XCORE_TILE=0 VERSION=2) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +set(TARGET_NAME tile1_example_freertos_dfu_v2) +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 ${APP_COMPILE_DEFINITIONS} THIS_XCORE_TILE=1 VERSION=2) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +#********************** +# Merge binaries +#********************** +merge_binaries(example_freertos_dfu_v1 tile0_example_freertos_dfu_v1 tile1_example_freertos_dfu_v1 1) +merge_binaries(example_freertos_dfu_v2 tile0_example_freertos_dfu_v2 tile1_example_freertos_dfu_v2 1) + +#********************** +# Create run and debug targets +#********************** +create_run_target(example_freertos_dfu_v1) +create_debug_target(example_freertos_dfu_v1) +create_flash_app_target( + #[[ Target ]] example_freertos_dfu_v1 + #[[ Boot Partition Size ]] 0x100000 + #[[ Data Parition Contents ]] + #[[ Dependencies ]] +) +query_tools_version() +create_upgrade_img_target(example_freertos_dfu_v1 ${XTC_VERSION_MAJOR} ${XTC_VERSION_MINOR}) +create_install_target(example_freertos_dfu_v1) +create_erase_all_target(example_freertos_dfu_v1 ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn) + +create_run_target(example_freertos_dfu_v2) +create_debug_target(example_freertos_dfu_v2) +create_flash_app_target( + #[[ Target ]] example_freertos_dfu_v2 + #[[ Boot Partition Size ]] 0x100000 + #[[ Data Parition Contents ]] + #[[ Dependencies ]] +) +create_upgrade_img_target(example_freertos_dfu_v2 ${XTC_VERSION_MAJOR} ${XTC_VERSION_MINOR}) +create_install_target(example_freertos_dfu_v2) +create_erase_all_target(example_freertos_dfu_v2 ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn) diff --git a/examples/freertos/dfu/src/FreeRTOSConfig.h b/examples/freertos/dfu/src/FreeRTOSConfig.h new file mode 100644 index 000000000..e45891dac --- /dev/null +++ b/examples/freertos/dfu/src/FreeRTOSConfig.h @@ -0,0 +1,113 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/* Here is a good place to include header files that are required across +your application. */ +#include "platform.h" + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 0 +#define configCPU_CLOCK_HZ 100000000 +#define configNUM_CORES 5 +#define configTICK_RATE_HZ 1000 +#define configMAX_PRIORITIES 32 +#define configRUN_MULTIPLE_PRIORITIES 1 +#define configUSE_TASK_PREEMPTION_DISABLE 1 +#define configUSE_CORE_AFFINITY 1 +#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 1256 +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 2 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ +#define configQUEUE_REGISTRY_SIZE 10 +#define configUSE_QUEUE_SETS 1 +#define configUSE_TIME_SLICING 1 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 /* Required for FreeRTOS_TCP_WIN.c TODO: active closed bug, may have been fixed upstream */ +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 +#define configSTACK_DEPTH_TYPE uint32_t +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t + + +/* Memory allocation related definitions. */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configTOTAL_HEAP_SIZE 256*1024 +#define configAPPLICATION_ALLOCATED_HEAP 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_MINIMAL_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configUSE_CORE_INIT_HOOK 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 0 +#define configUSE_STATS_FORMATTING_FUNCTIONS 2 /* Setting to 2 does not include in tasks.c */ + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 1 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE << 2 ) + +/* Define to trap errors during development. */ +#define configASSERT(x) xassert(x) + +/* Define to enable debug_printf() */ +#define configENABLE_DEBUG_PRINTF 1 + +/* Define to map sprintf and snprintf to the + * lite versions in lib_rtos_support */ + #include +#define configUSE_DEBUG_SPRINTF 1 + +/* Define to enable debug prints from tasks.c */ +#if ON_TILE(0) +#define configTASKS_DEBUG 0 +#endif +#if ON_TILE(1) +#define configTASKS_DEBUG 0 +#endif + +/* FreeRTOS MPU specific definitions. */ +#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xResumeFromISR 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xQueueGetMutexHolder 1 + +/* A header file that defines trace macro can be included here. */ +// #include "xcore_trace.h" + +#endif /* FREERTOS_CONFIG_H */ diff --git a/examples/freertos/dfu/src/app_conf.h b/examples/freertos/dfu/src/app_conf.h new file mode 100644 index 000000000..9d3762515 --- /dev/null +++ b/examples/freertos/dfu/src/app_conf.h @@ -0,0 +1,38 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef APP_CONF_H_ +#define APP_CONF_H_ + +/* Intertile Communication Configuration */ +#define appconfI2C_MASTER_RPC_PORT 10 +#define appconfI2C_MASTER_RPC_PRIORITY (configMAX_PRIORITIES/2) + +#define appconfGPIO_T0_RPC_PORT 11 +#define appconfGPIO_T1_RPC_PORT 12 +#define appconfGPIO_RPC_PRIORITY (configMAX_PRIORITIES/2) + +/* I/O and interrupt cores for Tile 0 */ +#define appconfI2C_IO_CORE 4 /* Must be kept off core 0 with the RTOS tick ISR */ +#define appconfI2C_INTERRUPT_CORE 0 /* Must be kept off I/O cores. */ +#define appconfXUD_IO_CORE 1 /* Must be kept off core 0 with the RTOS tick ISR */ +#define appconfUSB_INTERRUPT_CORE 3 /* Must be kept off I/O cores. Best kept off core 0 with the tick ISR. */ +#define appconfUSB_SOF_INTERRUPT_CORE 4 /* Must be kept off I/O cores. Best kept off cores with other ISRs. */ +#define appconfSPI_IO_CORE 4 /* Must be kept off core 0 with the RTOS tick ISR */ +#define appconfSPI_INTERRUPT_CORE 0 /* Must be kept off I/O cores. */ + +/* I/O and interrupt cores for Tile 1 */ +#define appconfUART_RX_IO_CORE 3 /* Must be kept off core 0 with the RTOS tick ISR */ +#define appconfUART_RX_INTERRUPT_CORE 4 /* Must be kept off I/O cores. Best kept off core 0 with the tick ISR. */ + +/* UART Configuration */ +#define appconfUART_BAUD_RATE 806400 + +/* Task Priorities */ +#define appconfSTARTUP_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define appconfSPI_MASTER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define appconfQSPI_FLASH_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define appconfUART_RX_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define appconfUSB_MANAGER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) + +#endif /* APP_CONF_H_ */ diff --git a/examples/freertos/dispatcher/src/config.xscope b/examples/freertos/dfu/src/config.xscope similarity index 96% rename from examples/freertos/dispatcher/src/config.xscope rename to examples/freertos/dfu/src/config.xscope index a16034781..bb71bfe23 100644 --- a/examples/freertos/dispatcher/src/config.xscope +++ b/examples/freertos/dfu/src/config.xscope @@ -20,5 +20,5 @@ - + diff --git a/examples/freertos/dfu/src/main.c b/examples/freertos/dfu/src/main.c new file mode 100644 index 000000000..e440adfe3 --- /dev/null +++ b/examples/freertos/dfu/src/main.c @@ -0,0 +1,118 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* System headers */ +#include +#include + +/* FreeRTOS headers */ +#include "FreeRTOS.h" +#include "queue.h" + +/* Library headers */ + +/* App headers */ +#include "app_conf.h" +#include "usb_support.h" +#include "xcore/channel_streaming.h" +#include "platform/platform_init.h" +#include "platform/driver_instances.h" + +void vApplicationMallocFailedHook( void ) +{ + rtos_printf("Malloc Failed on tile %d!\n", THIS_XCORE_TILE); + for(;;); +} + +void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { + rtos_printf("\nStack Overflow!!! %d %s!\n", THIS_XCORE_TILE, pcTaskName); + configASSERT(0); +} + +void blinky_task(void *arg) { + uint32_t gpio_port = rtos_gpio_port(PORT_LEDS); + uint32_t led_val = 0; + + rtos_gpio_port_enable(gpio_ctx_t0, gpio_port); + + for (;;) { + rtos_gpio_port_out(gpio_ctx_t0, gpio_port, led_val); + led_val ^= VERSION; + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +void startup_task(void *arg) +{ + rtos_printf("Startup task running from tile %d on core %d\n", THIS_XCORE_TILE, portGET_CORE_ID()); + + platform_start(); + +#if ON_TILE(0) + rtos_dfu_image_print_debug(dfu_image_ctx); + + uint32_t data; + rtos_qspi_flash_read( + qspi_flash_ctx, + (uint8_t*)&data, + rtos_dfu_image_get_data_partition_addr(dfu_image_ctx), + sizeof(int32_t)); + rtos_printf("First word at data partition start is: 0x%x\n", data); +#endif + + for (;;) { + rtos_printf("Tile[%d]:\n\tMinimum heap free: %d\n\tCurrent heap free: %d\n", THIS_XCORE_TILE, xPortGetMinimumEverFreeHeapSize(), xPortGetFreeHeapSize()); + vTaskDelay(pdMS_TO_TICKS(5000)); + } +} + +void vApplicationMinimalIdleHook(void) +{ + rtos_printf("idle hook on tile %d core %d\n", THIS_XCORE_TILE, rtos_core_id_get()); + asm volatile("waiteu"); +} + +void tile_common_init(chanend_t c) +{ + platform_init(c); + chanend_free(c); + + xTaskCreate((TaskFunction_t) startup_task, + "startup_task", + RTOS_THREAD_STACK_SIZE(startup_task), + NULL, + appconfSTARTUP_TASK_PRIORITY, + NULL); + +#if ON_TILE(0) + xTaskCreate((TaskFunction_t) blinky_task, + "blinky_task", + RTOS_THREAD_STACK_SIZE(blinky_task), + NULL, + appconfSTARTUP_TASK_PRIORITY / 2, + NULL); +#endif + + rtos_printf("start scheduler on tile %d\n", THIS_XCORE_TILE); + vTaskStartScheduler(); +} + +#if ON_TILE(0) +void main_tile0(chanend_t c0, chanend_t c1, chanend_t c2, chanend_t c3) { + (void)c0; + (void)c2; + (void)c3; + + tile_common_init(c1); +} +#endif + +#if ON_TILE(1) +void main_tile1(chanend_t c0, chanend_t c1, chanend_t c2, chanend_t c3) { + (void)c1; + (void)c2; + (void)c3; + + tile_common_init(c0); +} +#endif diff --git a/examples/freertos/dfu/src/tusb_config.h b/examples/freertos/dfu/src/tusb_config.h new file mode 100644 index 000000000..21fe4c315 --- /dev/null +++ b/examples/freertos/dfu/src/tusb_config.h @@ -0,0 +1,50 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#ifndef TUSB_CONFIG_H_ +#define TUSB_CONFIG_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "app_conf.h" + +//-------------------------------------------------------------------- +// COMMON CONFIGURATION +//-------------------------------------------------------------------- + +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) +#define CFG_TUSB_OS OPT_OS_CUSTOM + +#ifndef CFG_TUSB_DEBUG +#define CFG_TUSB_DEBUG 0 +#endif + +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(8))) + +#define CFG_TUSB_DEBUG_PRINTF rtos_printf + +//-------------------------------------------------------------------- +// DEVICE CONFIGURATION +//-------------------------------------------------------------------- + +#define CFG_TUD_EP_MAX 12 +#define CFG_TUD_TASK_QUEUE_SZ 8 +#define CFG_TUD_ENDPOINT0_SIZE 64 + +#define CFG_TUD_XCORE_INTERRUPT_CORE appconfUSB_INTERRUPT_CORE +#define CFG_TUD_XCORE_SOF_INTERRUPT_CORE appconfUSB_SOF_INTERRUPT_CORE +#define CFG_TUD_XCORE_IO_CORE_MASK (1 << appconfXUD_IO_CORE) + +//------------- CLASS -------------// +#define CFG_TUD_DFU 1 + +// DFU buffer size, it has to be set to the buffer size used in TUD_DFU_DESCRIPTOR +#define CFG_TUD_DFU_XFER_BUFSIZE 4096 + +#ifdef __cplusplus + } +#endif + +#endif /* TUSB_CONFIG_H_ */ diff --git a/examples/freertos/dfu/src/usb/app_dfu.c b/examples/freertos/dfu/src/usb/app_dfu.c new file mode 100644 index 000000000..316f72c8c --- /dev/null +++ b/examples/freertos/dfu/src/usb/app_dfu.c @@ -0,0 +1,264 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include +#include +#include + +#include "FreeRTOS.h" +#include "timers.h" +#include "platform/driver_instances.h" +#include "tusb.h" + +/* + * After device is enumerated in dfu mode run the following commands + * + * To transfer firmware from host to device + * + * $ dfu-util -d cafe -a 0 -D [filename] + * $ dfu-util -d cafe -a 1 -D [filename] + * + * To transfer firmware from device to host: + * + * $ dfu-util -d cafe -a 0 -U [filename] + * $ dfu-util -d cafe -a 1 -U [filename] + * + */ + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF PROTYPES +//--------------------------------------------------------------------+ +static void reboot(void); + +//--------------------------------------------------------------------+ +// Device callbacks +//--------------------------------------------------------------------+ + +// Invoked when device is mounted +void tud_mount_cb(void) +{ + rtos_printf("mounted\n"); +} + +// Invoked when device is unmounted +void tud_umount_cb(void) +{ + rtos_printf("unmounted\n"); +} + +// Invoked when usb bus is suspended +// remote_wakeup_en : if host allow us to perform remote wakeup +// Within 7ms, device must draw an average of current less than 2.5 mA from bus +void tud_suspend_cb(bool remote_wakeup_en) +{ + (void) remote_wakeup_en; + rtos_printf("suspended\n"); +} + +// Invoked when usb bus is resumed +void tud_resume_cb(void) +{ + rtos_printf("resumed\n"); +} + +//--------------------------------------------------------------------+ +// 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. +uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state) +{ + if ( state == DFU_DNBUSY ) { + return 10; // 10 ms + } else if (state == DFU_MANIFEST) { + // since we don't buffer entire image and do any flashing in manifest stage + return 0; + } + + return 0; +} + +// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests +// This callback could be returned before flashing op is complete (async). +// 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; + } +} + +// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) +// Application can do checksum, or actual flashing if buffered entire image previously. +// 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; + + // 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); +} + +// Invoked when received DFU_UPLOAD request +// Application must populate data with up to length bytes and +// 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; +} + +// Invoked when the Host has terminated a download or upload transfer +void tud_dfu_abort_cb(uint8_t alt) +{ + (void) alt; + rtos_printf("Host aborted transfer\n"); +} + +// Invoked when a DFU_DETACH request is received +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/freertos/dfu/src/usb/usb_descriptors.c b/examples/freertos/dfu/src/usb/usb_descriptors.c new file mode 100644 index 000000000..503e0cc1c --- /dev/null +++ b/examples/freertos/dfu/src/usb/usb_descriptors.c @@ -0,0 +1,173 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "tusb.h" +#include "class/dfu/dfu_device.h" + +/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug. + * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC. + * + * Auto ProductID layout's Bitmap: + * [MSB] HID | MSC | CDC [LSB] + */ +#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) ) +#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ + _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) + +//--------------------------------------------------------------------+ +// Device Descriptors +//--------------------------------------------------------------------+ +tusb_desc_device_t const desc_device = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + + #if CFG_TUD_CDC + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + #else + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + #endif + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = 0xCafe, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, + + .bNumConfigurations = 0x01 +}; + +// Invoked when received GET DEVICE DESCRIPTOR +// Application return pointer to descriptor +uint8_t const * tud_descriptor_device_cb(void) +{ + return (uint8_t const *) &desc_device; +} + +//--------------------------------------------------------------------+ +// Configuration Descriptor +//--------------------------------------------------------------------+ + +// Number of Alternate Interface (each for 1 flash partition) +#define ALT_COUNT 3 + +enum +{ + ITF_NUM_DFU_MODE, + ITF_NUM_TOTAL +}; + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_DFU_DESC_LEN(ALT_COUNT)) + +#define FUNC_ATTRS (DFU_ATTR_CAN_UPLOAD | DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_WILL_DETACH | DFU_ATTR_MANIFESTATION_TOLERANT) + +uint8_t const desc_configuration[] = +{ + // Config number, interface count, string index, total length, attribute, power in mA + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), + + // Interface number, Alternate count, starting string index, attributes, detach timeout, transfer size + TUD_DFU_DESCRIPTOR(ITF_NUM_DFU_MODE, ALT_COUNT, 4, FUNC_ATTRS, 1000, CFG_TUD_DFU_XFER_BUFSIZE), +}; + + +// Invoked when received GET CONFIGURATION DESCRIPTOR +// Application return pointer to descriptor +// Descriptor contents must exist long enough for transfer to complete +uint8_t const * tud_descriptor_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + return desc_configuration; +} + +//--------------------------------------------------------------------+ +// String Descriptors +//--------------------------------------------------------------------+ + +// array of pointer to string descriptors +char const* string_desc_arr [] = +{ + (const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409) + "TinyUSB", // 1: Manufacturer + "TinyUSB Device", // 2: Product + "123456", // 3: Serials, should use chip ID + "DFU dev FACTORY v" XCORE_UTILS_STRINGIFY(VERSION), // 4: DFU device + "DFU dev UPGRADE v" XCORE_UTILS_STRINGIFY(VERSION), // 5: DFU device + "DFU dev DATAPARTITION v" XCORE_UTILS_STRINGIFY(VERSION), // 6: DFU device +}; + +static uint16_t _desc_str[32]; + +// Invoked when received GET STRING DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + (void) langid; + + size_t chr_count; + + if ( index == 0) + { + memcpy(&_desc_str[1], string_desc_arr[0], 2); + chr_count = 1; + } + else + { + // Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors + + if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL; + + const char* str = string_desc_arr[index]; + + // Cap at max char + chr_count = strlen(str); + if ( chr_count > 31 ) { + chr_count = 31; + } + + // Convert ASCII string into UTF-16 + for(uint8_t i=0; i in tasks.c */ - -/* Co-routine related definitions. */ -#define configUSE_CO_ROUTINES 0 -#define configMAX_CO_ROUTINE_PRIORITIES 1 - -/* Software timer related definitions. */ -#define configUSE_TIMERS 1 -#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) -#define configTIMER_QUEUE_LENGTH 10 -#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE << 2) - -/* Define to trap errors during development. */ -#define configASSERT(x) xassert(x) - -/* Define to enable debug_printf() */ -#define configENABLE_DEBUG_PRINTF 1 - -/* Define to map sprintf and snprintf to the - * lite versions in lib_rtos_support */ -#include -#define configUSE_DEBUG_SPRINTF 1 - -/* Define to enable debug prints from tasks.c */ -#define configTASKS_DEBUG 1 - -/* FreeRTOS MPU specific definitions. */ -#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 - -/* Optional functions - most linkers will remove unused functions anyway. */ -#define INCLUDE_vTaskPrioritySet 1 -#define INCLUDE_uxTaskPriorityGet 1 -#define INCLUDE_vTaskDelete 1 -#define INCLUDE_vTaskSuspend 1 -#define INCLUDE_xResumeFromISR 1 -#define INCLUDE_vTaskDelayUntil 1 -#define INCLUDE_vTaskDelay 1 -#define INCLUDE_xTaskGetSchedulerState 1 -#define INCLUDE_xTaskGetCurrentTaskHandle 1 -#define INCLUDE_uxTaskGetStackHighWaterMark 1 -#define INCLUDE_xTaskGetIdleTaskHandle 1 -#define INCLUDE_eTaskGetState 1 -#define INCLUDE_xEventGroupSetBitFromISR 1 -#define INCLUDE_xTimerPendFunctionCall 1 -#define INCLUDE_xTaskAbortDelay 1 -#define INCLUDE_xTaskGetHandle 1 -#define INCLUDE_xTaskResumeFromISR 1 -#define INCLUDE_xQueueGetMutexHolder 1 - -/* A header file that defines trace macro can be included here. */ -//#include "xcore_trace.h" - -#endif /* FREERTOS_CONFIG_H */ diff --git a/examples/freertos/dispatcher/src/main.c b/examples/freertos/dispatcher/src/main.c deleted file mode 100644 index ad1e1b1fc..000000000 --- a/examples/freertos/dispatcher/src/main.c +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2021 XMOS LIMITED. This Software is subject to the terms of the -// XMOS Public License: Version 1 -#include -#include - -#include "FreeRTOS.h" -#include "task.h" - -#include "dispatcher.h" - -#define NUM_THREADS 4 -#define ROWS 100 // must be a multiple of NUM_THREADS -#define COLUMNS 100 - -typedef struct worker_arg -{ - int start_row; - int end_row; -} worker_arg_t; - -static int input_mat1[ROWS][COLUMNS]; -static int input_mat2[ROWS][COLUMNS]; -static int output_mat[ROWS][COLUMNS]; - -void reset_matrices() -{ - for (int i = 0; i < ROWS; i++) - for (int j = 0; j < COLUMNS; j++) - { - input_mat1[i][j] = 1; - input_mat2[i][j] = 1; - output_mat[i][j] = 0; - } -} - -int verify_output_matrix() -{ - int num_errors = 0; - for (int i = 0; i < ROWS; i++) - { - for (int j = 0; j < COLUMNS; j++) - { - if (output_mat[i][j] != ROWS) - { - rtos_printf("Whoops! output_mat[%d][%d] equals %d, expected %d\n", i, j, - output_mat[i][j], ROWS); - num_errors += 1; - } - } - } - - return num_errors; -} - -DISPATCHER_JOB_ATTRIBUTE -void do_matrix_multiply(void *p) -{ - worker_arg_t *arg = (worker_arg_t *)p; - - for (int i = arg->start_row; i < arg->end_row; i++) - for (int j = 0; j < COLUMNS; j++) - for (int k = 0; k < ROWS; k++) - output_mat[i][j] += (input_mat1[i][k] * input_mat2[k][j]); -} - -void matrix_multiply() -{ - dispatcher_t *disp; - dispatch_group_t *group; - dispatch_job_t *jobs[NUM_THREADS]; - worker_arg_t job_args[NUM_THREADS]; - - reset_matrices(); - - // create the dispatcher - disp = dispatcher_create(); - - // initialize the dispatcher - dispatcher_thread_init(disp, NUM_THREADS, NUM_THREADS, - configMAX_PRIORITIES - 1); - - // create group - group = dispatch_group_create(NUM_THREADS); - - int num_rows = ROWS / NUM_THREADS; - for (int i = 0; i < NUM_THREADS; i++) - { - job_args[i].start_row = i * num_rows; - job_args[i].end_row = job_args[i].start_row + num_rows; - - jobs[i] = dispatch_job_create(do_matrix_multiply, (void *)&job_args[i]); - // add job to group - dispatch_group_job_add(group, jobs[i]); - } - - // dispatch the group - dispatcher_group_add(disp, group); - - // wait in this thread for all jobs in the group to finish - dispatcher_group_wait(disp, group); - - // verify the output matrix - if (verify_output_matrix() == 0) - rtos_printf("Congratulations, output matrix verified!\n"); - - // free memory - for (int i = 0; i < NUM_THREADS; i++) - { - dispatch_job_delete(jobs[i]); - } - - dispatch_group_delete(group); - dispatcher_delete(disp); - - vTaskDelete(NULL); -} - -void vApplicationMallocFailedHook(void) { debug_printf("Malloc failed!\n"); } - -void main_tile0(chanend_t c0, chanend_t c1, chanend_t c2, chanend_t c3) -{ - xTaskCreate(matrix_multiply, "MatrixMultiplyExample", 1024, NULL, - configMAX_PRIORITIES - 1, NULL); - vTaskStartScheduler(); -} diff --git a/examples/freertos/explorer_board/README.rst b/examples/freertos/explorer_board/README.rst index 85a47aef9..bcae400d5 100644 --- a/examples/freertos/explorer_board/README.rst +++ b/examples/freertos/explorer_board/README.rst @@ -44,13 +44,13 @@ From the xcore_sdk build folder, create the filesystem and flash the device with .. code-block:: console - make flash_fs_example_freertos_explorer_board + make flash_app_example_freertos_explorer_board .. tab:: Windows .. code-block:: console - nmake flash_fs_example_freertos_explorer_board + nmake flash_app_example_freertos_explorer_board ******************** Running the firmware diff --git a/examples/freertos/explorer_board/explorer_board.cmake b/examples/freertos/explorer_board/explorer_board.cmake index b4b7243e0..a2e5010d4 100644 --- a/examples/freertos/explorer_board/explorer_board.cmake +++ b/examples/freertos/explorer_board/explorer_board.cmake @@ -70,6 +70,7 @@ merge_binaries(example_freertos_explorer_board tile0_example_freertos_explorer_b #********************** create_run_target(example_freertos_explorer_board) create_debug_target(example_freertos_explorer_board) +create_install_target(example_freertos_explorer_board) #********************** # Filesystem support targets @@ -102,11 +103,9 @@ else() endif() create_filesystem_target(example_freertos_explorer_board) - -add_custom_target(flash_fs_example_freertos_explorer_board - COMMAND xflash --quad-spi-clock 50MHz --factory example_freertos_explorer_board.xe --boot-partition-size 0x100000 --data example_freertos_explorer_board_fat.fs - DEPENDS make_fs_example_freertos_explorer_board - COMMENT - "Flash filesystem" - VERBATIM +create_flash_app_target( + #[[ Target ]] example_freertos_explorer_board + #[[ Boot Partition Size ]] 0x100000 + #[[ Data Parition Contents ]] example_freertos_explorer_board_fat.fs + #[[ Dependencies ]] make_fs_example_freertos_explorer_board ) diff --git a/examples/freertos/explorer_board/src/example_pipeline/example_pipeline.c b/examples/freertos/explorer_board/src/example_pipeline/example_pipeline.c index 5bc4b9ba0..17e2540e6 100644 --- a/examples/freertos/explorer_board/src/example_pipeline/example_pipeline.c +++ b/examples/freertos/explorer_board/src/example_pipeline/example_pipeline.c @@ -103,7 +103,7 @@ void stage0(int32_t * audio_frame) // convert dB to amplitude float power = (float)xStage0_Gain / 20.0; float gain_fl = powf(10.0, power); - float_s32_t gain = float_to_float_s32(gain_fl); + float_s32_t gain = f32_to_float_s32(gain_fl); // scale both channels bfp_s32_scale(&ch0, &ch0, gain); bfp_s32_scale(&ch1, &ch1, gain); diff --git a/examples/freertos/explorer_board/src/example_pipeline/example_pipeline.h b/examples/freertos/explorer_board/src/example_pipeline/example_pipeline.h index e8a51e6e1..3e54bbf10 100644 --- a/examples/freertos/explorer_board/src/example_pipeline/example_pipeline.h +++ b/examples/freertos/explorer_board/src/example_pipeline/example_pipeline.h @@ -6,7 +6,7 @@ #include "rtos_mic_array.h" #include "rtos_i2s.h" -#include "bfp_math.h" +#include "xmath/xmath.h" enum { GET_GAIN_VAL = 1, diff --git a/examples/freertos/explorer_board/src/gpio_ctrl/gpio_ctrl.c b/examples/freertos/explorer_board/src/gpio_ctrl/gpio_ctrl.c index a21de283d..dc3230c0c 100644 --- a/examples/freertos/explorer_board/src/gpio_ctrl/gpio_ctrl.c +++ b/examples/freertos/explorer_board/src/gpio_ctrl/gpio_ctrl.c @@ -107,7 +107,7 @@ void gpio_ctrl(void) buttons_val = rtos_gpio_port_in(gpio_ctx_t0, button_port); led_val = rtos_gpio_port_in(gpio_ctx_t0, led_port); - + /* Mask out LED 2*/ led_val &= 0x4; led_val |= (~ buttons_val) & 0x3; @@ -118,7 +118,7 @@ void gpio_ctrl(void) buttonA = ( buttons_val >> 0 ) & 0x01; buttonB = ( buttons_val >> 1 ) & 0x01; - /* Adjust volume based on LEDs */ + /* Adjust volume based on buttons */ if( buttonA == 0 ) /* Up */ { xTimerStart( volume_up_timer, 0 ); diff --git a/examples/freertos/getting_started/getting_started.cmake b/examples/freertos/getting_started/getting_started.cmake index aa5dcb80d..6448b5ea4 100644 --- a/examples/freertos/getting_started/getting_started.cmake +++ b/examples/freertos/getting_started/getting_started.cmake @@ -68,3 +68,4 @@ merge_binaries(example_freertos_getting_started tile0_example_freertos_getting_s #********************** create_run_target(example_freertos_getting_started) create_debug_target(example_freertos_getting_started) +create_install_target(example_freertos_getting_started) diff --git a/examples/freertos/iot/README.rst b/examples/freertos/iot/README.rst index 0e47bf2a3..65d1e1011 100644 --- a/examples/freertos/iot/README.rst +++ b/examples/freertos/iot/README.rst @@ -17,7 +17,7 @@ here: https://mosquitto.org/download/. .. note:: - You can modify the example code to connect to a different MQTT broker. When doing so, you will also need to modify the filesystem setup scripts before running them. THis is to ensure that the correct client certificate, private key, and CA certificate are flashed. See ``filesystem_support/create_fs.sh`` and the instructions for setting up the filesystem below. + You can modify the example code to connect to a different MQTT broker. When doing so, you will also need to modify the filesystem setup scripts before running them. This is to ensure that the correct client certificate, private key, and CA certificate are flashed. See ``filesystem_support/create_fs.sh`` and the instructions for setting up the filesystem below. Next, configure the example software to connect to the proper MQTT broker. If you are running the MQTT broker on your local PC, you will need to know that PC's IP address. This can be determined a number of ways including: @@ -108,6 +108,6 @@ To turn LED 0 on run: .. code-block:: console - mosquitto_pub --cafile mqtt_broker_certs/ca.crt --cert mqtt_broker_certs/client.crt --key mqtt_broker_certs/client.key -d -t "explorer/ledctrl" -m "{"LED": "0",: "status": "on"}" + mosquitto_pub -h localhost -p 8883 --cafile mqtt_broker_certs/ca.crt --cert mqtt_broker_certs/client.crt --key mqtt_broker_certs/client.key -d -t "explorer/ledctrl" -m '{"LED": "0", "status": "on"}' Supported values for "LED" are ["0", "1", "2", "3"], supported values for "status" are ["on", "off"]. diff --git a/examples/freertos/iot/iot.cmake b/examples/freertos/iot/iot.cmake index 2971f4ad3..b8c7ea485 100644 --- a/examples/freertos/iot/iot.cmake +++ b/examples/freertos/iot/iot.cmake @@ -85,6 +85,7 @@ merge_binaries(example_freertos_iot tile0_example_freertos_iot tile1_example_fre #********************** create_run_target(example_freertos_iot) create_debug_target(example_freertos_iot) +create_install_target(example_freertos_iot) #********************** # Filesystem support targets diff --git a/examples/freertos/l2_cache/l2_cache.cmake b/examples/freertos/l2_cache/l2_cache.cmake index 45e752431..bb23fe3d2 100644 --- a/examples/freertos/l2_cache/l2_cache.cmake +++ b/examples/freertos/l2_cache/l2_cache.cmake @@ -57,6 +57,7 @@ target_link_options(example_freertos_l2_cache PRIVATE ${APP_LINK_OPTIONS}) #********************** create_run_target(example_freertos_l2_cache) create_debug_target(example_freertos_l2_cache) +create_install_target(example_freertos_l2_cache) #********************** # Extract swmem diff --git a/examples/freertos/tracealyzer/README.rst b/examples/freertos/tracealyzer/README.rst new file mode 100644 index 000000000..4643a4186 --- /dev/null +++ b/examples/freertos/tracealyzer/README.rst @@ -0,0 +1,358 @@ +################################ +FreeRTOS Tracealyzer Example +################################ + +This is a simple multi-tile FreeRTOS example application illustrating how to use +FreeRTOS' trace functionality with Percepio's Tracealyzer. The application +illustrates a timeout issue in an example state machine which can be +visualized/diagnosed with Tracealyzer. In the absence of Tracealyzer, it is +possible to define another trace implementation, see `FreeRTOS Trace Macros`_ +documentation for more details. For such instances, an ASCII trace +implementation is available as a good starting point. This can be enabled by +changing the trace mode define in the cmake file to: +`USE_TRACE_MODE=TRACE_MODE_XSCOPE_ASCII`. + +The application starts the FreeRTOS scheduler running on both `tile[0]` and +`tile[1]`. `tile[0]` has 11 tasks, whereas `tile[1]` has only 1 task running. +Both `tile[0]` and `tile[1]` share the same logic for a "hello" task which +prints a message every second. The other 10 `tile[0]` tasks serve to demonstrate +an issue that can be introduced on command by the user by interacting with the +buttons on the xCORE.AI Explorer board. Pressing button 1 will increase a +counter up to a maximum value of 8 (while button 0 decreases this counter down +to a minimum value of 0). This value affects how many `subprocess` tasks +sequentially interrupt the main `process` task. The main `process` task monitors +timing while in its `RUN` state. If it detects an interruption greater than or +equal to a configured threshold, the `process` will momentarily transition to +a `timeout` state. Pressing Button 1 four or more consecutive times should +result in this timeout event. Using tools such as Tracealyzer reduces the effort +involved in diagnosing multi-core/task applications. + +**************************** +Limitations and Known Issues +**************************** + +The following are the currently known issues/limitations for this example: + +- Tracing is performed on a single tile at a time. In this example, Tracealyzer + is setup on `tile[0]`. +- Tracealyzer's snapshot mode is not supported. +- It may be necessary to disable certain trace events (see `trcConfig.h`), + limit user events (i.e. via xTracePrint), or disable additional xSCOPE probes + to reduce the bandwidth requirements over xSCOPE. In some cases the + application may exit prematurely or drop trace data when there are + exceptionally high number of trace events being recorded. This behavior may be + attributed to the host PC's USB controller or general performance factors + regarding the offloading of trace data from the XTAG. In such cases, + xscope2psf will log a "missing events" warning. + +********************* +Building the Host App +********************* + +Run the following commands in the root folder to build the host application +using your native x86 Toolchain: + +.. note:: + + Permissions may be required to install the host applications. + +Linux or Mac +------------ + + .. code-block:: console + + cmake -B build_host + cd build_host + make xscope2psf + make install + +The host application, `xscope2psf`, will be installed at `/opt/xmos/SDK//bin/`, +and may be moved if desired. + +Windows +------- + + .. code-block:: console + + cmake -G "NMake Makefiles" -B build_host + cd build_host + nmake xscope2psf + nmake install + +The host application, `xscope2psf.exe`, will be install at `%USERPROFILE%\.xmos\SDK\\bin\\`, +and may be moved if desired. + +The instructions that follow will assume that the path of this binary has been +added to your `PATH` variable or the binary has been copied to the current +directory. + +********************* +Building the Firmware +********************* + +Run the following commands in the xcore_sdk root folder to build the firmware: + +Linux or Mac +------------ + + .. code-block:: console + + cmake -B build -DCMAKE_TOOLCHAIN_FILE=xmos_cmake_toolchain/xs3a.cmake + cd build + make example_freertos_tracealyzer + +Windows +------- + + .. code-block:: console + + cmake -G "NMake Makefiles" -B build -DCMAKE_TOOLCHAIN_FILE=xmos_cmake_toolchain/xs3a.cmake + cd build + nmake example_freertos_tracealyzer + +********************* +Running the Firmware +********************* + +From the xcore_sdk build folder run: + +Linux or Mac +------------ + + .. code-block:: console + + make run_xscope_to_file_example_freertos_tracealyzer + +Windows +------- + + .. code-block:: console + + nmake run_xscope_to_file_example_freertos_tracealyzer + +If successful, the console should have printed a subset of messages similar to +the following: + + .. code-block:: console + + Hello task running from tile 1 on core 4 + Entered subprocess task (7) on core 3 + Entered subprocess task (6) on core 4 + Entered subprocess task (5) on core 5 + Entered subprocess task (4) on core 0 + Entered subprocess task (3) on core 2 + Entered subprocess task (2) on core 3 + Entered subprocess task (1) on core 4 + Entered subprocess task (0) on core 5 + Entered main process on core 0 + Hello task running from tile 0 on core 2 + Entered gpio task on core 1 + Hello from tile 0 + Hello from tile 1 + Hello from tile 0 + Hello from tile 1 + +The LED behavior should be as follows: + +- LED 0 should turn on while Button 0 is pressed. +- LED 1 should turn on while Button 0 is pressed. +- LED 2 should toggle when the main process enters the timeout state. +- LED 3 should toggle every 500ms. + +There should also be two new files generated: + +- freertos_trace.vcd +- freertos_trace.gtkw + +********************************* +Generating a Tracealyzer PSF File +********************************* + +With the previously generated `freertos_trace.vcd` file, from the xcore_sdk +build directory run: + + .. code-block:: console + + xscope2psf -v -i freertos_trace.vcd -o freertos_trace.psf + +The output from this command should look similar to what is shown below: + + .. code-block:: console + + Opening input file ... + Opening output file ... + Processing file (Probe: 0) ... + [PSF Header] + - Format Version: 0x000A + - Options: 0x00000000 + - Number of Cores: 6 + - Platform: FreeRTOS + - Platform ID: 0x1AA1 + - Platform Config: 1.0 Patch 0 + - ISR Tail-Chaining Threshold: 0 + [PSF Timestamp] + - Type: 1 + - Frequency: 100000000 + - Period: 100000 + - Wraparounds: 0 + - OS Tick Hz: 1000 + - Latest Timestamp: 0 + - OS Tick Count: 0 + End of file reached. + Read 282879 lines. + Processed 70714 events. + Closing files ... + Done. + +Successful execution of this command will produce the Percepio Streaming Format +(PSF) file that can be opened in Tracealyzer for inspection. + +************************************ +Live Trace Visualization (streaming) +************************************ + +The previous steps illustrated a way to save a VCD trace to disk and post +process it. Alternatively, this workflow can be changed to visualize the trace +live. Two methods are currently available for this which will be discussed in +this section. + +Before continuing, Tracealyzer must be configured to use the 'File System` as +the PSF streaming option. This can be configured via the following steps: + +1. From the menubar in Tracealyzer, click `File` --> `Settings` +2. In the `Settings` window's left-hand menu tree, click `Project Settings` + --> `PSF Streaming Settings`. +3. Under `Target Connection` select `File System`. +4. This setting will provide an option to specify a PSF file. Specify the + `freertos_trace.psf` file that was previously generated. +5. Click `OK`. +6. From the menubar, click `Trace` --> `Open Live Stream Tool`. +7. This will open a new `Live Stream` window, in this window click `Connect`. + +With the xrun/xgdb `example_freertos_tracealyzer.xe` and `xscope2psf` +applications still running, it should now be possible to click `Start Session` +and see the trace data live. Alternatively, the `Start` and `Stop` recording +button in the main window's left hand menu bar may be utilized for control. + +.. note:: + + The `Live Stream` window's reported `Event Rate` and `Data Rate` is useful + when optimizing xscope bandwidth utilization and to determine if it is + necessary to limit the frequency or types of events being recorded. A + `Data Rate` versus time graph can be shown in this window via the menubar's + `View` --> `Data Rate` option. + + +Using --xscope-file +------------------- + +From the xcore_sdk build folder run: + +1. Start the application: + + .. code-block:: console + + xrun --xscope-file freertos_trace example_freertos_tracealyzer.xe + +2. Start the PSF file generation process: + + .. code-block:: console + + xscope2psf -v -s -i freertos_trace.vcd -o freertos_trace.psf + +As the VCD file is being written to (via xscope), xscope2psf will produce status +updates on the number of lines processed and how many events have been written +to the PSF file. The console output will look similar to the following: + + .. code-block:: console + + Opening input file ... + Opening output file ... + Processing file (Probe: 0) ... + [PSF Header] + - Format Version: 0x000A + - Options: 0x00000000 + - Number of Cores: 6 + - Platform: FreeRTOS + - Platform ID: 0x1AA1 + - Platform Config: 1.0 Patch 0 + - ISR Tail-Chaining Threshold: 0 + [PSF Timestamp] + - Type: 1 + - Frequency: 100000000 + - Period: 100000 + - Wraparounds: 0 + - OS Tick Hz: 1000 + - Latest Timestamp: 0 + - OS Tick Count: 0 + [STREAM STATUS] + - Read 33027 lines + - Processed 8251 events + [STREAM STATUS] + - Read 41359 lines + - Processed 10334 events + [STREAM STATUS] + - Read 47431 lines + - Processed 11852 events + [STREAM STATUS] + - Read 56771 lines + - Processed 14187 events + +Using --xscope-port +------------------- + +1. Start the application: + + .. code-block:: console + + xrun --xscope-port localhost:10234 example_freertos_tracealyzer.xe + +2. Start the PSF file generation process: + + .. code-block:: console + xscope2psf -v -I localhost:10234 -o freertos_trace.psf + +As record data is sent to xscope2psf it will produce status updates on the +number of events written to the PSF file. The console output will look similar +to the following: + + .. code-block:: console + + Configuring xscope callbacks ... + Opening output file ... + Connecting to xscope (Probe: 0, Host: localhost, Port: 10234) ... + [REGISTERED] Probe ID: 0, Name: 'freertos_trace' + [PSF Header] + - Format Version: 0x000A + - Options: 0x00000000 + - Number of Cores: 6 + - Platform: FreeRTOS + - Platform ID: 0x1AA1 + - Platform Config: 1.0 Patch 0 + - ISR Tail-Chaining Threshold: 0 + [PSF Timestamp] + - Type: 1 + - Frequency: 100000000 + - Period: 100000 + - Wraparounds: 0 + - OS Tick Hz: 1000 + - Latest Timestamp: 0 + - OS Tick Count: 0 + [STREAM STATUS] + - Processed 162 events + [STREAM STATUS] + - Processed 1585 events + [STREAM STATUS] + - Processed 3902 events + [STREAM STATUS] + - Processed 5288 events + +In this case the target application's `printf` output will not be present in +either xrun/xgdb or xscope2psf (while xscope2psf is connected). This output can +be emitted on xscope2psf by providing the `--print-endpoint` option. It is +recommended to use the `-p` and `-v` options separately as the current +implementation of this utility does not provide any measures to ensure the +target's printf log entries are not interrupted by the regular stream status +reporting. + +.. _FreeRTOS Trace Macros: https://www.freertos.org/rtos-trace-macros.html \ No newline at end of file diff --git a/examples/freertos/dispatcher/XCORE-AI-EXPLORER.xn b/examples/freertos/tracealyzer/XCORE-AI-EXPLORER.xn similarity index 100% rename from examples/freertos/dispatcher/XCORE-AI-EXPLORER.xn rename to examples/freertos/tracealyzer/XCORE-AI-EXPLORER.xn diff --git a/examples/freertos/tracealyzer/host/CMakeLists.txt b/examples/freertos/tracealyzer/host/CMakeLists.txt new file mode 100644 index 000000000..ba67eaee7 --- /dev/null +++ b/examples/freertos/tracealyzer/host/CMakeLists.txt @@ -0,0 +1,54 @@ +cmake_minimum_required(VERSION 3.20) + +project(xscope2psf LANGUAGES C) +set(TARGET_NAME xscope2psf) + +set(FATFS_HOST_PATH "${CMAKE_CURRENT_LIST_DIR}") + +file(READ ${XCORE_SDK_ROOT}/settings.json JSON_STRING) +# Get the "version" value from the JSON element +string(JSON VERSION_VAL GET ${JSON_STRING} ${IDX} version) + +# Determine OS, set up output dirs +if(${CMAKE_SYSTEM_NAME} STREQUAL Linux) + set(XSCOPE2PSF_INSTALL_DIR "/opt/xmos/SDK/${VERSION_VAL}/bin") +elseif(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) + set(XSCOPE2PSF_INSTALL_DIR "/opt/xmos/SDK/${VERSION_VAL}/bin") +elseif(${CMAKE_SYSTEM_NAME} STREQUAL Windows) + set(XSCOPE2PSF_INSTALL_DIR "$ENV{USERPROFILE}\\.xmos\\SDK\\${VERSION_VAL}\\bin") +endif() + +set(APP_SOURCES + "${CMAKE_CURRENT_LIST_DIR}/xscope2psf.c" +) + +set(APP_INCLUDES + "$ENV{XMOS_TOOL_PATH}/include/" +) + +find_library(XSCOPE_ENDPOINT_LIB NAMES xscope_endpoint.so xscope_endpoint.lib + PATHS $ENV{XMOS_TOOL_PATH}/lib) + +add_executable(${TARGET_NAME}) + +target_sources(${TARGET_NAME} PRIVATE ${APP_SOURCES}) +target_include_directories(${TARGET_NAME} PRIVATE ${APP_INCLUDES}) +target_link_libraries(${TARGET_NAME} PRIVATE ${XSCOPE_ENDPOINT_LIB}) +install(TARGETS ${TARGET_NAME} DESTINATION ${XSCOPE2PSF_INSTALL_DIR}) + +if ((CMAKE_C_COMPILER_ID STREQUAL "Clang") OR (CMAKE_C_COMPILER_ID STREQUAL "AppleClang")) + message(STATUS "Configuring for Clang") + target_compile_options(${TARGET_NAME} PRIVATE -O2 -Wall) + target_link_options(${TARGET_NAME} PRIVATE "") +elseif (CMAKE_C_COMPILER_ID STREQUAL "GNU") + message(STATUS "Configuring for GCC") + target_compile_options(${TARGET_NAME} PRIVATE -O2 -Wall) + target_link_options(${TARGET_NAME} PRIVATE "") +elseif (CMAKE_C_COMPILER_ID STREQUAL "MSVC") + message(STATUS "Configuring for MSVC") + target_compile_options(${TARGET_NAME} PRIVATE /W3) + target_link_options(${TARGET_NAME} PRIVATE "") + add_compile_definitions(_CRT_SECURE_NO_WARNINGS=1) +else () + message(FATAL_ERROR "Unsupported compiler: ${CMAKE_C_COMPILER_ID}") +endif() diff --git a/examples/freertos/tracealyzer/host/xscope2psf.c b/examples/freertos/tracealyzer/host/xscope2psf.c new file mode 100644 index 000000000..69d48d0ad --- /dev/null +++ b/examples/freertos/tracealyzer/host/xscope2psf.c @@ -0,0 +1,875 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include +#include +#include +#include +#include +#include "xscope_endpoint.h" + +#define VERSION "1.0.1" + +// Abstraction for sleep portability +#if defined(__GNUC__) || defined(__MINGW32__) +#include +#define SLEEP_MS(x) usleep((x) * 1000) +#else +#include +#define SLEEP_MS(x) Sleep(x) +#endif + +#define XSTR(s) STR(s) +#define STR(x) #x +#define NUM_ELEMS(x) (sizeof(x) / sizeof(x[0])) + +/* + * The xscope probe to process on. + * Tracealyzer's trcStreamPort.c is currently expected to call xscope_bytes() + * for probe ID 0. + */ +#define XSCOPE_PROBE_ID 0 + +#define MAX_LINE_BUFFER_BYTES 4096 + +/* + * Enables additional informational logging while processing the PSF data. + * This is mainly for development purposes. + */ +#define PRINT_PSF_EVENTS 0 + +/* + * Enables printing records for probes other than XSCOPE_PROBE_ID when + * the `--in-port` option is specified. This is mainly for development + * purposes. + */ +#define PRINT_OTHER_RECORDS 0 + +typedef enum error_code { + ERROR_NONE, + ERROR_INTERNAL, + ERROR_MUTUALLY_EXCLUSIVE_ARGS, + ERROR_MISSING_ARG, + ERROR_UNKOWN_ARG, + ERROR_ARG_VALUE_MISSING, + ERROR_ARG_VALUE_PARSING_FAILURE, + ERROR_NOT_OPT_OR_FLAG, + ERROR_INCOMPATIBLE_VCD, + ERROR_DATA_TOO_SHORT, + ERROR_FILE_SYSTEM, + ERROR_OUT_OF_RESOURCES +} error_code_t; + +typedef enum log_level { + LOG_INF = 0x1, + LOG_WRN = 0x2, + LOG_ERR = 0x4 +} log_level_t; + +typedef enum process_psf_state { + PROCESS_PSF_HEADER, + PROCESS_PSF_TIMESTAMP, + PROCESS_PSF_EVENT_TABLE_HEADER, + PROCESS_PSF_EVENT_TABLE_ENTRY, + PROCESS_PSF_EVENT +} process_psf_state_t; + +typedef enum parsing_vcd_state { + PARSING_VCD_HEADER, + PARSING_VCD_RECORDS +} parsing_vcd_state_t; + +// Type taken from from Tracealyzer sources. +typedef struct TraceHeader { + uint32_t uiPSF; + uint16_t uiVersion; + uint16_t uiPlatform; + uint32_t uiOptions; + uint32_t uiNumCores; + uint32_t isrTailchainingThreshold; + char platformCfg[8]; + uint16_t uiPlatformCfgPatch; + uint8_t uiPlatformCfgMinor; + uint8_t uiPlatformCfgMajor; +} TraceHeader_t; + +// Type taken from from Tracealyzer sources. +typedef struct TraceTimestamp +{ + uint32_t type; + uint32_t frequency; + uint32_t period; + uint32_t wraparounds; + uint32_t osTickHz; + uint32_t latestTimestamp; + uint32_t osTickCount; +} TraceTimestamp_t; + +// A derivative of TraceEntryTable_t defined in trcEntryTable.c +typedef struct TraceEntryTableHeader +{ + uint32_t uiSlots; + uint32_t uiEntrySymbolLength; + uint32_t uiEntryStateCount; +} TraceEntryTableHeader_t; + +/* + * The available command line argument flags/options. + */ +static const char *help_arg[] = {"-h", "--help"}; +static const char *version_arg[] = {"--version"}; +static const char *verbose_arg[] = {"-v", "--verbose"}; +static const char *stream_arg[] = {"-s", "--stream"}; +static const char *print_endpoint_arg[] = {"-p", "--print-endpoint"}; +static const char *delay_arg[] = {"-d", "--delay"}; +static const char *input_file_arg[] = {"-i", "--in-file"}; +static const char *input_port_arg[] = {"-I", "--in-port"}; +static const char *output_file_arg[] = {"-o", "--out-file"}; + +static bool running = true; +static int event_count = 0; +static long long line_count = 0; +static process_psf_state_t psf_state = PROCESS_PSF_HEADER; +static TraceEntryTableHeader_t psf_evt_table; +static uint32_t psf_evt_entry = 0; +static uint16_t *event_cnts = NULL; +static uint16_t num_cores; + +/* + * Variables set by command line arguments. + */ +static log_level_t log_level = LOG_WRN; +static bool show_help = false; +static bool show_version = false; +static bool stream_mode = false; +static bool print_endpoint = false; +static int sleep_ms = 1000; +static char *input_host = NULL; +static char *input_port = NULL; +static char *input_filename = NULL; +static char *output_filename = NULL; +static FILE *out_file = NULL; + +static void print_help(char *arg0) +{ + printf("Usage:\n"); + printf(" %s [-h] [--version]\n\n", arg0); + printf(" %s [-v] [-s] [-d ] -i -o \n\n", + arg0); + printf(" %s [-v] [-p] -I : -o \n\n", arg0); + printf("Generate a Percepio Streaming Format (PSF) file based on Tracealyzer data received\n" + "via an xscope Value Change Dump (VCD) file or an xscope endpoint socket connection.\n\n"); + printf("Options:\n"); + printf(" -h, --help This help menu.\n"); + printf(" --version Print the version of this tool.\n"); + printf(" -v, --verbose Print verbose output.\n"); + printf(" -s, --stream Once the end of a file has been reached,\n" + " continue to wait for more data. Terminate\n" + " execution via Ctrl+C or other means.\n"); + printf(" -p, --print-endpoint When using -in-port, this option will enable\n" + " reception of printf data on this xscope endpoint.\n"); + printf(" -d, --delay The time in milliseconds to sleep when waiting for more\n" + " data on the input file stream. This option only applies\n" + " for --stream. Default = 1000.\n"); + printf(" -i, --in-file The VCD file to process. In stream mode, the\n" + " application will wait for such a file to exist.\n"); + printf(" -I, --in-port : The host and port (separated by ':') on the which\n" + " xgdb's --xscope-port is serving on.\n" + " Note: --stream is implied when using this mode.\n"); + printf(" -o, --out-file The PSF file to generate.\n"); +} + +static void write_log(log_level_t level, const char *format, ...) +{ + va_list args; + va_start(args, format); + + if (level >= log_level) { + switch (level) { + case LOG_WRN: + printf("WARNING: "); + break; + case LOG_ERR: + printf("ERROR: "); + break; + default: + break; + } + vprintf(format, args); + } + va_end(args); +} + +static void print_stream_status(void) +{ + write_log(LOG_INF, "[STREAM STATUS]\n"); + + if (input_filename) + write_log(LOG_INF, "- Read %lld lines\n", line_count); + + write_log(LOG_INF, "- Processed %d events\n", event_count + 1); +} + +static void print_psf_header(TraceHeader_t *header) +{ + write_log(LOG_INF, "[PSF Header]\n"); + write_log(LOG_INF, "- Format Version: 0x%04X\n", header->uiVersion); + write_log(LOG_INF, "- Options: 0x%08X\n", header->uiOptions); + write_log(LOG_INF, "- Number of Cores: %d\n", header->uiNumCores); + write_log(LOG_INF, "- Platform: %.8s\n", header->platformCfg); + write_log(LOG_INF, "- Platform ID: 0x%04X\n", header->uiPlatform); + write_log(LOG_INF, "- Platform Config: %d.%d Patch %d\n", + header->uiPlatformCfgMajor, header->uiPlatformCfgMinor, + header->uiPlatformCfgPatch); + write_log(LOG_INF, "- ISR Tail-Chaining Threshold: %d\n", + header->isrTailchainingThreshold); +} + +static void print_psf_timestamp(TraceTimestamp_t *timestamp) +{ + write_log(LOG_INF, "[PSF Timestamp]\n"); + write_log(LOG_INF, "- Type: %d\n", timestamp->type); + write_log(LOG_INF, "- Frequency: %d\n", timestamp->frequency); + write_log(LOG_INF, "- Period: %d\n", timestamp->period); + write_log(LOG_INF, "- Wraparounds: %d\n", timestamp->wraparounds); + write_log(LOG_INF, "- OS Tick Hz: %d\n", timestamp->osTickHz); + write_log(LOG_INF, "- Latest Timestamp: %d\n", timestamp->latestTimestamp); + write_log(LOG_INF, "- OS Tick Count: %d\n", timestamp->osTickCount); +} + +#if (PRINT_PSF_EVENTS == 1) +static void print_psf_event(unsigned char trace_bytes[], int num_trace_bytes) +{ + printf("[PSF EVENT] TS: 0x%02X%02X%02X%02X, Core: %d, Cnt: 0x%01X%02X, ID = 0x%02X%02X, Data Len: %3d, Data:", + trace_bytes[7], trace_bytes[6], trace_bytes[5], trace_bytes[4], + trace_bytes[3] >> 4, + trace_bytes[3] & 0xF, trace_bytes[2], + trace_bytes[1], trace_bytes[0], + num_trace_bytes - 8); + + for (int i = 0; i < num_trace_bytes - 8; i++) + printf(" %02X", trace_bytes[i + 8]); + + printf("\n"); +} + +static void print_psf_event_table_header(unsigned char trace_bytes[], + int trace_length) +{ + write_log(LOG_INF, "[PSF Event Table]\n"); + write_log(LOG_INF, "- Slots: %d\n", psf_evt_table.uiSlots); + write_log(LOG_INF, "- Entry Symbol Length: %d\n", + psf_evt_table.uiEntrySymbolLength); + write_log(LOG_INF, "- Entry State Count: %d\n", + psf_evt_table.uiEntryStateCount); +} + +static void print_psf_event_table_entry(unsigned char trace_bytes[], + int trace_length) +{ + uint32_t states_offset = sizeof(uint32_t); + uint32_t options_offset = + (psf_evt_table.uiEntryStateCount + 1) * sizeof(uint32_t); + uint32_t symbol_offset = options_offset + sizeof(uint32_t); + + write_log(LOG_INF, "[PSF Event Entry]\n"); + write_log(LOG_INF, "- Address: 0x%02X%02X%02X%02X\n", trace_bytes[3], + trace_bytes[2], trace_bytes[1], trace_bytes[0]); + write_log(LOG_INF, "- States:"); + for (uint32_t i = 0; i < psf_evt_table.uiEntryStateCount; i++) { + write_log(LOG_INF, " 0x%02X%02X%02X%02X", + trace_bytes[(i * sizeof(uint32_t)) + states_offset + 3], + trace_bytes[(i * sizeof(uint32_t)) + states_offset + 2], + trace_bytes[(i * sizeof(uint32_t)) + states_offset + 1], + trace_bytes[(i * sizeof(uint32_t)) + states_offset]); + } + write_log(LOG_INF, "\n"); + write_log(LOG_INF, "- Options: 0x%02X%02X%02X%02X\n", + trace_bytes[options_offset + 3], trace_bytes[options_offset + 2], + trace_bytes[options_offset + 1], trace_bytes[options_offset]); + write_log(LOG_INF, "- Symbol: %.*s\n", psf_evt_table.uiEntrySymbolLength, + &trace_bytes[symbol_offset]); +} +#endif /* (PRINT_PSF_EVENTS == 1) */ + +static void print_record(unsigned int id, unsigned long long timestamp, + unsigned int length, unsigned long long data_val, + unsigned char *data_bytes) +{ + write_log(LOG_INF, "[PROBE %d] 0x%016llX ==> %lld", id, timestamp, + data_val); + for (unsigned int i = 0; i < length; i++) { + if ((i == 0) || (i % 16) == 0) + write_log(LOG_INF, "\n\t"); + else if ((i % 8) == 0) + write_log(LOG_INF, " "); + + write_log(LOG_INF, "%02X ", data_bytes[i]); + } + + write_log(LOG_INF, "\n"); +} + +static error_code_t process_psf_header(unsigned char trace_bytes[], + int trace_length) +{ + const uint32_t expected_bom = 0x50534600; + TraceHeader_t header; + + /* The xscope probe's first record should be the PSF header in + * its entirety. */ + if (trace_length != sizeof(TraceHeader_t)) { + write_log(LOG_ERR, "Incompatible PSF header length detected.\n"); + return ERROR_INCOMPATIBLE_VCD; + } + + memcpy(&header, trace_bytes, sizeof(TraceHeader_t)); + + // The magic cookie/BOM should always be "\0FSP" on xcore + if (header.uiPSF != expected_bom) { + write_log(LOG_ERR, "Incompatible PSF BOM detected.\n"); + return ERROR_INCOMPATIBLE_VCD; + } + + print_psf_header(&header); + + if (header.uiNumCores > 0) { + uint16_t data_size = header.uiNumCores * sizeof(uint16_t); + event_cnts = malloc(data_size); + + if (event_cnts == NULL) + return ERROR_OUT_OF_RESOURCES; + + num_cores = header.uiNumCores; + + /* Set each event count to 0xFFFF which is an invalid value + * for the 12-bit counter. */ + memset(event_cnts, 0xFF, data_size); + } + + return ERROR_NONE; +} + +static error_code_t process_psf_timestamp(unsigned char trace_bytes[], + int trace_length) +{ + TraceTimestamp_t timestamp; + + if (trace_length != sizeof(TraceTimestamp_t)) { + write_log(LOG_ERR, "Incompatible PSF timestamp length detected.\n"); + return ERROR_INCOMPATIBLE_VCD; + } + + memcpy(×tamp, trace_bytes, sizeof(TraceTimestamp_t)); + print_psf_timestamp(×tamp); + return ERROR_NONE; +} + +static error_code_t process_psf_event_table_header(unsigned char trace_bytes[], + int trace_length) +{ + if (trace_length != sizeof(TraceEntryTableHeader_t)) { + write_log(LOG_ERR, + "Incompatible PSF event table header length detected.\n"); + return ERROR_INCOMPATIBLE_VCD; + } + + memcpy(&psf_evt_table, trace_bytes, sizeof(TraceEntryTableHeader_t)); + +#if (PRINT_PSF_EVENTS == 1) + print_psf_event_table_header(trace_bytes, trace_length); +#endif + + return ERROR_NONE; +} + +static error_code_t process_psf_event_table_entry(unsigned char trace_bytes[], + int trace_length) +{ + uint32_t expected_len = + (psf_evt_table.uiEntryStateCount + 2) * sizeof(uint32_t) + + psf_evt_table.uiEntrySymbolLength; + if (trace_length != expected_len) { + write_log(LOG_ERR, + "Incompatible PSF event table header length detected.\n"); + return ERROR_INCOMPATIBLE_VCD; + } + +#if (PRINT_PSF_EVENTS == 1) + print_psf_event_table_entry(trace_bytes, trace_length); +#endif + + return ERROR_NONE; +} + +static void detect_missing_events(unsigned char trace_bytes[], + int num_trace_bytes) +{ + const int core_id_offset = 3; + const int evt_cnt_offset_lo = 2; + const int evt_cnt_offset_hi = 3; + const int hi_evt_cnt_mask = 0x0F; + const uint16_t invalid_evt_cnt = 0xFFFF; + + uint16_t core_id = trace_bytes[core_id_offset] >> 4; + + if (event_cnts == NULL || core_id >= num_cores) + return; + + uint16_t event_cnt = + ((trace_bytes[evt_cnt_offset_hi] & hi_evt_cnt_mask) << 8) | + trace_bytes[evt_cnt_offset_lo]; + + if (event_cnts[core_id] != invalid_evt_cnt) + { + uint16_t event_cnt_delta = + (event_cnt > event_cnts[core_id]) ? + (event_cnt - event_cnts[core_id]) : + ((0x1000 - event_cnts[core_id]) + event_cnt); + + if (event_cnt_delta > 1) + write_log(LOG_WRN, + "Detected %d missing events (Core %d @ Current %d).\n", + event_cnt_delta - 1, core_id, event_cnt); + } + + event_cnts[core_id] = event_cnt; +} + +static void modify_trace_event_count(unsigned char trace_bytes[], + int num_trace_bytes) +{ + const int core_id_offset = 3; + const int evt_cnt_offset_lo = 2; + const int evt_cnt_offset_hi = 3; + const int core_id_mask = 0xF0; + const int hi_evt_cnt_mask = 0x0F; + char *evt_cnt = (char *)&event_count; + + /* + * Modify the event counter while retaining core id. The trace's event + * count is only 12-bit; however, a larger datatype is used by the + * application in order to provide a status report for indicating the + * total number of events processed. + * NOTE: This data is part of TraceBaseEvent_t and is assembled via + * TRC_EVENT_SET_EVENT_COUNT in the Tracealyzer unit. + */ + + trace_bytes[evt_cnt_offset_lo] = evt_cnt[0]; + trace_bytes[evt_cnt_offset_hi] = + (trace_bytes[core_id_offset] & core_id_mask) | + (evt_cnt[1] & hi_evt_cnt_mask); + event_count++; +} + +static error_code_t process_trace_event(unsigned char trace_bytes[], + int num_trace_bytes) +{ + /* + * Tracealyzer's FreeRTOS unit tracks event data on a per-core basis; + * however, when viewing all cores simultaneously in Tracealyzer, the event + * counter needs to be to be monotonically increasingly. + */ + + // Protect against accessing stale/garbage data + if (num_trace_bytes < 4) { + // Provide the line number in the file when processing a VCD file. + if (input_filename) { + write_log(LOG_WRN, + "Trace event data length too small (line %lld).\n", + line_count); + } else { + write_log(LOG_WRN, "Trace event data length too small.\n"); + } + + return ERROR_DATA_TOO_SHORT; + } + +#if (PRINT_PSF_EVENTS == 1) + print_psf_event(trace_bytes, num_trace_bytes); +#endif + + detect_missing_events(trace_bytes, num_trace_bytes); + modify_trace_event_count(trace_bytes, num_trace_bytes); + + return ERROR_NONE; +} + +static error_code_t process_psf_data(unsigned char trace_bytes[], + int trace_length) +{ + error_code_t res = ERROR_NONE; + + /* + * Tracealyzer's prvSetRecorderEnabled() calls a sequence of functions that + * write various metadata to the PSF file before events are written. + * The state machine below handles this logic. + */ + + switch (psf_state) { + case PROCESS_PSF_HEADER: + res = process_psf_header(trace_bytes, trace_length); + psf_state = PROCESS_PSF_TIMESTAMP; + break; + case PROCESS_PSF_TIMESTAMP: + res = process_psf_timestamp(trace_bytes, trace_length); + psf_state = PROCESS_PSF_EVENT_TABLE_HEADER; + break; + case PROCESS_PSF_EVENT_TABLE_HEADER: + res = process_psf_event_table_header(trace_bytes, trace_length); + psf_state = PROCESS_PSF_EVENT_TABLE_ENTRY; + break; + case PROCESS_PSF_EVENT_TABLE_ENTRY: + psf_evt_entry++; + res = process_psf_event_table_entry(trace_bytes, trace_length); + + if (psf_evt_entry >= psf_evt_table.uiSlots) { + psf_state = PROCESS_PSF_EVENT; + } + break; + case PROCESS_PSF_EVENT: + res = process_trace_event(trace_bytes, trace_length); + break; + default: + res = ERROR_INTERNAL; + break; + } + + return res; +} + +static error_code_t process_vcd_file(FILE *input_file, FILE *output_file) +{ + int last_event_count = 0; + parsing_vcd_state_t parsing_state = PARSING_VCD_HEADER; + char line[MAX_LINE_BUFFER_BYTES]; + + while (1) { + const char delim[] = " \n\r"; + char *line_ptr = fgets(line, sizeof(line), input_file); + + if (line_ptr == NULL) { + if (!stream_mode) + break; + + if (last_event_count != event_count) { + print_stream_status(); + last_event_count = event_count; + } + + SLEEP_MS(sleep_ms); + continue; + } + + line_count++; + + /* Filter lines related to VCD header; afterwards, only process lines + * that begin with 'l' which are expected to be run-length encoded + * hex-strings representing the Tracealyzer PSF data. */ + if (parsing_state == PARSING_VCD_HEADER) { + char *token = strtok(line, delim); + const char *end_of_header = "$enddefinitions"; + + if (strcmp(token, end_of_header) == 0) + parsing_state = PARSING_VCD_RECORDS; + + continue; + } else { + bool is_trace_data = (line[0] == 'l'); + if (!is_trace_data) + continue; + } + + // The first token indicates the length of the data that follows + char *len_field = strtok(line, delim); + + // The second token has the trace data that needs to be converted + char *trace_data = strtok(NULL, delim); + + /* The third token indicates the probe ID. Skip lines not targeting the + * expected probe ID. */ + char *scope_probe = strtok(NULL, delim); + + if (len_field == NULL || trace_data == NULL || scope_probe == NULL) { + write_log(LOG_WRN, "Unexpected encoding (line %lld).\n", + line_count); + continue; + } + + if (strcmp(scope_probe, XSTR(XSCOPE_PROBE_ID)) != 0) + continue; + + int trace_data_chars = strlen(trace_data); + int decoded_trace_len; + + if ((sscanf(len_field, "l%d", &decoded_trace_len) != 1) || + (trace_data_chars != (decoded_trace_len << 1))) { + write_log(LOG_WRN, "Unexpected encoding (line %lld).\n", + line_count); + continue; + } + + unsigned char trace_bytes[MAX_LINE_BUFFER_BYTES >> 1]; + + // Convert the trace_data from a hex-string to an array of bytes + for (int i = 0; i < decoded_trace_len; i++) + sscanf(&trace_data[i << 1], "%02hhx", &trace_bytes[i]); + + error_code_t res = process_psf_data(trace_bytes, decoded_trace_len); + if (res != ERROR_NONE && res != ERROR_DATA_TOO_SHORT) + return res; + + if (fwrite(trace_bytes, sizeof(trace_bytes[0]), decoded_trace_len, + output_file) != decoded_trace_len) + write_log(LOG_ERR, "Data lost while writing to file system.\n"); + } + + if (feof(input_file) && !stream_mode) { + write_log(LOG_INF, "End of file reached.\n"); + write_log(LOG_INF, "Read %lld lines.\n", line_count); + write_log(LOG_INF, "Processed %d events.\n", event_count + 1); + } + + return ERROR_NONE; +} + +static void xscope_exit_cb(void) +{ + running = false; +} + +static void xscope_register_cb(unsigned int id, unsigned int type, + unsigned int r, unsigned int g, unsigned int b, + unsigned char *name, unsigned char *unit, + unsigned int data_type, unsigned char *data_name) +{ + if (!running) + return; + + write_log(LOG_INF, "[REGISTERED] Probe ID: %d, Name: '%s'\n", id, name); +} + +static void xscope_print_cb(unsigned long long timestamp, unsigned int length, + unsigned char *data) +{ + if (!running || (length == 0)) + return; + + printf("[PRINT] "); + + for (unsigned i = 0; i < length; i++) + printf("%c", data[i]); +} + +static void xscope_record_cb(unsigned int id, unsigned long long timestamp, + unsigned int length, unsigned long long data_val, + unsigned char *data_bytes) +{ + if (!running) + return; + + if (id == XSCOPE_PROBE_ID) { + error_code_t res = process_psf_data(data_bytes, length); + if (res != ERROR_NONE && res != ERROR_DATA_TOO_SHORT) { + running = false; + return; + } + + if (fwrite(data_bytes, sizeof(data_bytes[0]), length, out_file) != + length) { + write_log(LOG_ERR, "Data lost while writing to file system.\n"); + } + } +#if (PRINT_OTHER_RECORDS == 1) + else { + print_record(id, timestamp, length, data_val, data_bytes); + } +#endif +} + +static bool is_matching_arg(char *arg, const char *arg_options[], + int num_options) +{ + for(int i = 0; i < num_options; i++) + { + if (0 == strcmp(arg, arg_options[i])) + return true; + } + + return false; +} + +static error_code_t next_arg_value(int argc, char *argv[], int *argi) +{ + if ((++(*argi) >= argc) || argv[*argi][0] == '-') { + write_log(LOG_ERR, "Missing argument value (%s).\n", argv[*argi - 1]); + return ERROR_ARG_VALUE_MISSING; + } + + return ERROR_NONE; +} + +static error_code_t process_args(int argc, char *argv[]) +{ + bool in_port_present = false; + bool in_file_present = false; + bool out_file_present = false; + + for (int i = 1; i < argc; i++) { + if (is_matching_arg(argv[i], help_arg, NUM_ELEMS(help_arg))) { + show_help = true; + return ERROR_NONE; + } else if (is_matching_arg(argv[i], version_arg, + NUM_ELEMS(version_arg))) { + show_version = true; + return ERROR_NONE; + } else if (is_matching_arg(argv[i], input_file_arg, + NUM_ELEMS(input_file_arg))) { + if (next_arg_value(argc, argv, &i) != ERROR_NONE) + return ERROR_ARG_VALUE_MISSING; + + input_filename = argv[i]; + in_file_present = true; + } else if (is_matching_arg(argv[i], input_port_arg, + NUM_ELEMS(input_port_arg))) { + if (next_arg_value(argc, argv, &i) != ERROR_NONE) + return ERROR_ARG_VALUE_MISSING; + + /* The argument follows similar format to --xscope-port, where + * the value specified follows the form :. */ + const char delims[] = ":"; + input_host = strtok(argv[i], delims); + input_port = strtok(NULL, delims); + in_port_present = (input_host && input_port); + } else if (is_matching_arg(argv[i], output_file_arg, + NUM_ELEMS(output_file_arg))) { + if (next_arg_value(argc, argv, &i) != ERROR_NONE) + return ERROR_ARG_VALUE_MISSING; + + output_filename = argv[i]; + out_file_present = true; + } else if (is_matching_arg(argv[i], print_endpoint_arg, + NUM_ELEMS(print_endpoint_arg))) { + print_endpoint = true; + } else if (is_matching_arg(argv[i], delay_arg, NUM_ELEMS(delay_arg))) { + if (next_arg_value(argc, argv, &i) != ERROR_NONE) + return ERROR_ARG_VALUE_MISSING; + + if (sscanf(argv[i], "%d", &sleep_ms) != 1) { + write_log(LOG_ERR, "Argument value (%s) could not be parsed.\n", + argv[i]); + return ERROR_ARG_VALUE_PARSING_FAILURE; + } + } else if (is_matching_arg(argv[i], stream_arg, + NUM_ELEMS(stream_arg))) { + stream_mode = true; + } else if (is_matching_arg(argv[i], verbose_arg, + NUM_ELEMS(verbose_arg))) { + log_level = LOG_INF; + } else { + write_log(LOG_ERR, "Unkown argument (%s).\n", argv[i]); + return ERROR_UNKOWN_ARG; + } + } + + if (in_port_present && in_file_present) + return ERROR_MUTUALLY_EXCLUSIVE_ARGS; + + return ((in_port_present || in_file_present) && out_file_present) ? + ERROR_NONE : + ERROR_MISSING_ARG; +} + +int main(int argc, char *argv[]) +{ + int exit_code = process_args(argc, argv); + FILE *in_file = NULL; + + if (show_help || exit_code) { + print_help(argv[0]); + return exit_code; + } else if (show_version) { + printf("version %s\n", VERSION); + return exit_code; + } + + // Setup the input data source based on the specified user arguments + if (input_filename) { + write_log(LOG_INF, "Opening input file ...\n"); + + while (1) { + in_file = fopen(input_filename, "r"); + + if (in_file != NULL) + break; + + if (stream_mode) { + SLEEP_MS(1000); + } else { + write_log(LOG_INF, "File not found.\n"); + return ERROR_FILE_SYSTEM; + } + } + } else { + write_log(LOG_INF, "Configuring xscope callbacks ...\n"); + + if (print_endpoint) + xscope_ep_set_print_cb(xscope_print_cb); + + xscope_ep_set_register_cb(xscope_register_cb); + xscope_ep_set_record_cb(xscope_record_cb); + xscope_ep_set_exit_cb(xscope_exit_cb); + } + + write_log(LOG_INF, "Opening output file ...\n"); + out_file = fopen(output_filename, "wb"); + + if (out_file == NULL) { + if (in_file != NULL) + fclose(in_file); + + return ERROR_FILE_SYSTEM; + } + + // Process the input data source based on the specified user arguments + if (input_filename) { + write_log(LOG_INF, "Processing file (Probe: %d) ...\n", + XSCOPE_PROBE_ID); + exit_code = process_vcd_file(in_file, out_file); + } else { + write_log(LOG_INF, + "Connecting to xscope (Probe: %d, Host: %s, Port: %s) ...\n", + XSCOPE_PROBE_ID, input_host, input_port); + int error = xscope_ep_connect(input_host, input_port); + if (error) { + running = false; + write_log(LOG_ERR, "Failed to connect to xscope (%d).\n", error); + } + + // While 'running' print out basic status info for user feedback. + int last_event_count = 0; + while (running) { + if (last_event_count != event_count) { + print_stream_status(); + last_event_count = event_count; + } + + SLEEP_MS(1000); + } + + write_log(LOG_INF, "Disconnecting from xscope ...\n"); + xscope_ep_disconnect(); + } + + write_log(LOG_INF, "Closing files ...\n"); + fclose(out_file); + if (in_file != NULL) + fclose(in_file); + + if (event_cnts != NULL) + free(event_cnts); + + write_log(LOG_INF, "Done.\n"); + + return exit_code; +} \ No newline at end of file diff --git a/examples/freertos/tracealyzer/src/FreeRTOSConfig.h b/examples/freertos/tracealyzer/src/FreeRTOSConfig.h new file mode 100644 index 000000000..22df55f56 --- /dev/null +++ b/examples/freertos/tracealyzer/src/FreeRTOSConfig.h @@ -0,0 +1,120 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/* Here is a good place to include header files that are required across +your application. */ +#include "platform.h" + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 0 +#define configCPU_CLOCK_HZ 100000000 + +#if ON_TILE(0) +#define configNUM_CORES 6 +#endif +#if ON_TILE(1) +#define configNUM_CORES 5 +#endif + +#define configTICK_RATE_HZ 1000 +#define configMAX_PRIORITIES 32 +#define configRUN_MULTIPLE_PRIORITIES 1 +#define configUSE_TASK_PREEMPTION_DISABLE 1 +#define configUSE_CORE_AFFINITY 1 +#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256 +#define configMAX_TASK_NAME_LEN 32 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 2 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ +#define configQUEUE_REGISTRY_SIZE 10 +#define configUSE_QUEUE_SETS 1 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 /* Required for FreeRTOS_TCP_WIN.c TODO: active closed bug, may have been fixed upstream */ +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 +#define configSTACK_DEPTH_TYPE uint32_t +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t + +/* Memory allocation related definitions. */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configTOTAL_HEAP_SIZE 128*1024 +#define configAPPLICATION_ALLOCATED_HEAP 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configUSE_CORE_INIT_HOOK 0 + +/* Run time and task stats gathering related definitions. */ +#if ON_TILE(0) +#define configGENERATE_RUN_TIME_STATS 1 +#define configUSE_TRACE_FACILITY 1 +#else +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 0 +#endif +#define configUSE_STATS_FORMATTING_FUNCTIONS 2 /* Setting to 2 does not include in tasks.c */ + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 1 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE ) + +/* Define to trap errors during development. */ +#define configASSERT(x) xassert(x) + +/* Define to enable debug_printf() */ +#define configENABLE_DEBUG_PRINTF 1 + +/* Define to map sprintf and snprintf to the + * lite versions in lib_rtos_support */ +#include +#define configUSE_DEBUG_SPRINTF 1 + +/* FreeRTOS MPU specific definitions. */ +#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xResumeFromISR 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xQueueGetMutexHolder 1 + +#if ((configUSE_TRACE_FACILITY == 1) && \ + (configGENERATE_RUN_TIME_STATS == 1)) + +/* A header file that defines trace macro can be included here. */ +#include "xcore_trace.h" + +#endif /* (configUSE_TRACE_FACILITY == 1) */ + +#endif /* FREERTOS_CONFIG_H */ diff --git a/examples/freertos/tracealyzer/src/config.xscope b/examples/freertos/tracealyzer/src/config.xscope new file mode 100644 index 000000000..16a1c6680 --- /dev/null +++ b/examples/freertos/tracealyzer/src/config.xscope @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/freertos/tracealyzer/src/main.c b/examples/freertos/tracealyzer/src/main.c new file mode 100644 index 000000000..d745003bb --- /dev/null +++ b/examples/freertos/tracealyzer/src/main.c @@ -0,0 +1,518 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#include +#include + +#include "FreeRTOS.h" +#include "task.h" + +#include "rtos_printf.h" + +#include "platform/platform_init.h" +#include "platform/driver_instances.h" + +/* + * Constants / Macros + */ + +typedef enum ProcessState { + STATE_IDLE, + STATE_SETUP, + STATE_RUN, + STATE_TIMEOUT +} ProcessState_t; + +#define STRINGIFY(str) #str + +#define REF_TMR_TICKS_PER_MS (PLATFORM_REFERENCE_HZ / 1000) +#define REF_TMR_TICKS_FROM_MS(x) ((x) * REF_TMR_TICKS_PER_MS) + +#define PROCESS_TIMEOUT_DELAY_MS 1000 // How long to stay in the timeout state +#define PROCESS_IDLE_DELAY_MS 500 // How long to stay in the timeout state +#define PROCESS_RUN_DELAY_MS 1 // The time between each "run" iteration/output value +#define PROCESS_RUN_ITERATIONS 2048 // (PROCESS_RUN_DELAY_MS * PROCESS_RUN_ITERATIONS) == min duration of "run" state. +#define PROCESS_WAVEFORM(x) (uint32_t)(1000 * sin(2 * M_PI * (x) / (PROCESS_RUN_ITERATIONS / 4)) + 1000) +#define PROCESS_TIMEOUT_TICKS REF_TMR_TICKS_FROM_MS(20) + +#define NUM_SUBPROCESS_TASKS 8 +#define SUBPROCESS_DELAY_TIME_MS 5 /* Represents the time a subprocess is running and + * effectively holding onto the mutex */ +#define SUBPROCESS_TIMER_MS 100 /* Time delay from when main process runs to when the + * first subprocess is notified. This time should not + * exceed (PROCESS_RUN_ITERATIONS * PROCESS_RUN_DELAY_MS) */ + +#define TASK_NOTIF_MASK_RUN_TASK 0x00010000 +#define TASK_NOTIF_MASK_HBEAT_TIMER 0x00000010 +#define TASK_NOTIF_MASK_TIMEOUT 0x00000020 +#define TASK_NOTIF_MASK_BTN_EVENT 0x00000004 +#define TASK_NOTIF_MASK_BTN_MASK 0x00000003 + +#define BUTTON_DEBOUNCE_MS 100 +#define BUTTON_DEBOUNCE_TICKS REF_TMR_TICKS_FROM_MS(BUTTON_DEBOUNCE_MS) +#define BUTTON0_PRESSED(notif_val) ((notif_val >> 0) & 0x01) +#define BUTTON1_PRESSED(notif_val) ((notif_val >> 1) & 0x01) + +#define LED_HBEAT_TIMER_MS 500 + +#define LED_MASK_BTN0 0x01 +#define LED_MASK_BTN1 0x02 +#define LED_MASK_TMO 0x04 +#define LED_MASK_HBEAT 0x08 + +#define LED_ASSERT(buf, mask) buf |= mask +#define LED_DEASSERT(buf, mask) buf &= ~mask +#define LED_TOGGLE(buf, mask) buf ^= mask +#define LED_UPDATE(cond, buf, mask) \ + do { \ + if (cond) { \ + LED_ASSERT(buf, mask); \ + } else { \ + LED_DEASSERT(buf, mask); \ + } \ + } while (0) + +/* + * If another trace implementation is being used, define + * TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH to give the buffer used to generate the + * subprocess task names a define size + */ +#ifndef TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH +#define TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH 32 +#endif + +/* + * Private Globals + */ + +static const UBaseType_t base_task_priority = + configMAX_PRIORITIES - NUM_SUBPROCESS_TASKS - 2; + +#if ON_TILE(0) + +#if (TRC_USE_TRACEALYZER_RECORDER == 1) +static ProcessState_t process_state_last = STATE_TIMEOUT; +static const char *states[] = { "Idle", "Setup", "Run", "Timeout" }; +#endif + +static TaskHandle_t ctx_gpio_task = NULL; +static TaskHandle_t ctx_process_task = NULL; +static TaskHandle_t ctx_subprocess_tasks[NUM_SUBPROCESS_TASKS] = { NULL }; +static SemaphoreHandle_t resource_mutex; +static uint8_t num_requested_subprocesses = 0; +static uint8_t num_subprocesses = 0; +static ProcessState_t process_state = STATE_IDLE; + +#if (TRC_USE_TRACEALYZER_RECORDER == 1) +static TraceStringHandle_t trc_main_state; +static TraceStringHandle_t trc_active_subprocesses; +static TraceStringHandle_t trc_run_iteration; +static TraceStringHandle_t trc_run_delta; +static TraceStringHandle_t trc_output; +#endif + +#endif /* ON_TILE(0) */ + +/* + * Forward Declarations + */ + +#if ON_TILE(0) +static inline uint32_t get_abs_delta(uint32_t current, uint32_t last); + +RTOS_GPIO_ISR_CALLBACK_ATTR +static void button_callback(rtos_gpio_t *ctx, void *app_data, + rtos_gpio_port_id_t port_id, uint32_t value); +static void on_btn0_event(uint8_t *num_subprocesses); +static void on_btn1_event(uint8_t *num_subprocesses); +static uint8_t is_btn_stable(uint32_t curr_btn_ticks, uint32_t *last_btn_ticks); + +static void hbeat_tmr_callback(TimerHandle_t pxTimer); +static void subprocess_tmr_callback(TimerHandle_t pxTimer); +static void spin_ref_tmr_ticks(uint32_t ticks); + +static void process_task(void *arg); +static void subprocess_task(void *arg); +static void gpio_task(void *arg); + +#endif /* ON_TILE(0) */ + +static void hello_task(void *arg); +static void tile_common_init(chanend_t c); + +/* + * Private Definitions + */ + +#if ON_TILE(0) + +static inline uint32_t get_abs_delta(uint32_t current, uint32_t last) +{ + return (current >= last) ? (current - last) : (UINT32_MAX - last + current); +} + +RTOS_GPIO_ISR_CALLBACK_ATTR +static void button_callback(rtos_gpio_t *ctx, void *app_data, + rtos_gpio_port_id_t port_id, uint32_t value) +{ + const uint32_t btn0Mask = 0x01; + const uint32_t btn1Mask = 0x02; + TaskHandle_t task = app_data; + BaseType_t xYieldRequired = pdFALSE; + + // Convert active-low logic to active-high + value = (~value) & (btn0Mask | btn1Mask); + + xTaskNotifyFromISR(task, (value | TASK_NOTIF_MASK_BTN_EVENT), + eSetValueWithOverwrite, &xYieldRequired); + portYIELD_FROM_ISR(xYieldRequired); +} + +static uint8_t is_btn_stable(uint32_t curr_btn_ticks, uint32_t *last_btn_ticks) +{ + uint32_t delta_ticks = get_abs_delta(curr_btn_ticks, *last_btn_ticks); + uint8_t btn_stable = (delta_ticks >= BUTTON_DEBOUNCE_TICKS); + *last_btn_ticks = curr_btn_ticks; + return btn_stable; +} + +static void on_btn0_event(uint8_t *num_subprocesses) +{ + if (*num_subprocesses > 0) { + (*num_subprocesses)--; +#if ((TRC_USE_TRACEALYZER_RECORDER == 1) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) + xTracePrintF(trc_active_subprocesses, "%d", *num_subprocesses); +#endif + rtos_printf("Num active subprocesses: %d\n", *num_subprocesses); + } +} + +static void on_btn1_event(uint8_t *num_subprocesses) +{ + if (*num_subprocesses < NUM_SUBPROCESS_TASKS) { + (*num_subprocesses)++; +#if ((TRC_USE_TRACEALYZER_RECORDER == 1) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) + xTracePrintF(trc_active_subprocesses, "%d", *num_subprocesses); +#endif + rtos_printf("Num active subprocesses: %d\n", *num_subprocesses); + } +} + +static void hbeat_tmr_callback(TimerHandle_t pxTimer) +{ + xTaskNotify(ctx_gpio_task, TASK_NOTIF_MASK_HBEAT_TIMER, eSetBits); +} + +static void subprocess_tmr_callback(TimerHandle_t pxTimer) +{ + if (num_subprocesses > 0) { + xTaskNotify(ctx_subprocess_tasks[0], TASK_NOTIF_MASK_RUN_TASK, + eSetBits); + } +} + +static void spin_ref_tmr_ticks(uint32_t ticks) +{ + uint32_t current_ticks = get_reference_time(); + uint32_t stop_ticks = current_ticks + ticks; + uint8_t rollover_condition = (stop_ticks < current_ticks); + + while (1) { + if (rollover_condition && (get_reference_time() < stop_ticks)) { + rollover_condition = 0; + } else if (get_reference_time() >= stop_ticks) { + break; + } + } +} + +static void process_task(void *arg) +{ + /* + * This value is used to limit how frequently to produce user event traces. + * Creating too many events may lead to data loss due to bandwidth + * limitations. This may be observed by closely inspecting the sinusoidal + * (or run iteration) waveform being generated in this example. In such + * cases, a sample will be held onto for a period of time and then there + * will be an "unexpected" phase jump. + */ + const uint8_t trace_subsample_count = 8; + + uint32_t current_run_ticks; + uint32_t last_run_ticks; + uint32_t delta_ticks; + uint32_t run_iteration; + TimerHandle_t tmr_subprocess; + + rtos_printf("Entered main process on core %d\n", portGET_CORE_ID()); + + tmr_subprocess = xTimerCreate(STRINGIFY(tmr_subprocess), + pdMS_TO_TICKS(SUBPROCESS_TIMER_MS), pdFALSE, + NULL, subprocess_tmr_callback); + + while (1) { +#if (TRC_USE_TRACEALYZER_RECORDER == 1) + if (process_state != process_state_last) { + process_state_last = process_state; + xTracePrint(trc_main_state, states[process_state]); + } +#endif + + switch (process_state) { + default: + case STATE_IDLE: + process_state = STATE_SETUP; + vTaskDelay(pdMS_TO_TICKS(PROCESS_IDLE_DELAY_MS)); + break; + + case STATE_SETUP: + num_subprocesses = num_requested_subprocesses; + /* + * Start a timer which will fire off a set of subtasks which will + * preempt this task during the "run" state. This will potentially + * cause a timing issue that the state logic will detect which can + * then be observed/inspected using Percepio's Tracealyzer. + */ + xTimerStart(tmr_subprocess, 0); + process_state = STATE_RUN; + last_run_ticks = get_reference_time(); + run_iteration = 0; + break; + + case STATE_RUN: + while (process_state == STATE_RUN) { + current_run_ticks = get_reference_time(); + delta_ticks = get_abs_delta(current_run_ticks, last_run_ticks); + last_run_ticks = current_run_ticks; + +#if ((TRC_USE_TRACEALYZER_RECORDER == 1) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) + if ((run_iteration % trace_subsample_count) == 1) { + xTracePrintF(trc_run_iteration, "%d", run_iteration); + } +#endif + + if (delta_ticks >= PROCESS_TIMEOUT_TICKS) { + process_state = STATE_TIMEOUT; + break; + } + +#if ((TRC_USE_TRACEALYZER_RECORDER == 1) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) + uint32_t output = PROCESS_WAVEFORM(run_iteration); + if ((run_iteration % trace_subsample_count) == 1) { + xTracePrintF(trc_output, "%d", output); + } +#endif + /* + * In this example, the main process and subprocesses use + * "spin_ref_tmr_ticks" as a means to convey a shared resource + * which takes some time to utilize. + */ + xSemaphoreTake(resource_mutex, portMAX_DELAY); + spin_ref_tmr_ticks(REF_TMR_TICKS_FROM_MS(PROCESS_RUN_DELAY_MS)); + xSemaphoreGive(resource_mutex); + + run_iteration++; + if (run_iteration >= PROCESS_RUN_ITERATIONS) { + process_state = STATE_IDLE; + } + } + + break; + + case STATE_TIMEOUT: + rtos_printf("Timeout!\n"); + xTaskNotify(ctx_gpio_task, TASK_NOTIF_MASK_TIMEOUT, eSetBits); + vTaskDelay(pdMS_TO_TICKS(PROCESS_TIMEOUT_DELAY_MS)); + process_state = STATE_SETUP; + break; + } + } +} + +static void subprocess_task(void *arg) +{ + const uint32_t bits_to_clear_on_entry = 0x00000000UL; + const uint32_t bits_to_clear_on_exit = 0xFFFFFFFFUL; + uint32_t notif_value; + uint8_t inst = ((uint32_t)arg - (uint32_t)ctx_subprocess_tasks) / + sizeof(TaskHandle_t); + uint8_t next_inst = inst + 1; + + rtos_printf("Entered subprocess task (%d) on core %d\n", inst, + portGET_CORE_ID()); + + while (1) { + xTaskNotifyWait(bits_to_clear_on_entry, bits_to_clear_on_exit, + ¬if_value, portMAX_DELAY); + + if (notif_value & TASK_NOTIF_MASK_RUN_TASK) { + xSemaphoreTake(resource_mutex, portMAX_DELAY); + spin_ref_tmr_ticks(REF_TMR_TICKS_FROM_MS(SUBPROCESS_DELAY_TIME_MS)); + + /* + * Notify before giving back the mutex to allow the higher priority + * task to queue up for the notification event. This allows the + * subprocesses to run sequentially, while keeping the main process + * task in a blocked state. + */ + if (next_inst < num_subprocesses) { + xTaskNotify(ctx_subprocess_tasks[next_inst], + TASK_NOTIF_MASK_RUN_TASK, eSetBits); + } + + xSemaphoreGive(resource_mutex); + } + } +} + +static void gpio_task(void *arg) +{ + const uint32_t bits_to_clear_on_entry = 0x00000000UL; + const uint32_t bits_to_clear_on_exit = 0xFFFFFFFFUL; + uint32_t led_val = 0; + uint32_t notif_value; + TimerHandle_t tmr_hbeat; + rtos_gpio_port_id_t p_leds = rtos_gpio_port(PORT_LEDS); + rtos_gpio_port_id_t p_btns = rtos_gpio_port(PORT_BUTTONS); + uint32_t btn0_debounce_tick_time = get_reference_time(); + uint32_t btn1_debounce_tick_time = btn0_debounce_tick_time; + + rtos_gpio_port_enable(gpio_ctx_t0, p_leds); + rtos_gpio_port_enable(gpio_ctx_t0, p_btns); + rtos_gpio_isr_callback_set(gpio_ctx_t0, p_btns, button_callback, + xTaskGetCurrentTaskHandle()); + rtos_gpio_interrupt_enable(gpio_ctx_t0, p_btns); + + tmr_hbeat = xTimerCreate(STRINGIFY(tmr_hbeat), + pdMS_TO_TICKS(LED_HBEAT_TIMER_MS), pdTRUE, NULL, + hbeat_tmr_callback); + + xTimerStart(tmr_hbeat, 0); + + rtos_printf("Entered gpio task on core %d\n", portGET_CORE_ID()); + + while (1) { + xTaskNotifyWait(bits_to_clear_on_entry, bits_to_clear_on_exit, + ¬if_value, portMAX_DELAY); + + if (notif_value & TASK_NOTIF_MASK_HBEAT_TIMER) { + LED_TOGGLE(led_val, LED_MASK_HBEAT); + } + + if (notif_value & TASK_NOTIF_MASK_TIMEOUT) { + LED_TOGGLE(led_val, LED_MASK_TMO); + } + + if (notif_value & TASK_NOTIF_MASK_BTN_EVENT) { + uint32_t current_ref_ticks = get_reference_time(); + + if (BUTTON0_PRESSED(notif_value) && + is_btn_stable(current_ref_ticks, &btn0_debounce_tick_time)) { + LED_ASSERT(led_val, LED_MASK_BTN0); + on_btn0_event(&num_requested_subprocesses); + } else { + LED_DEASSERT(led_val, LED_MASK_BTN0); + btn0_debounce_tick_time = current_ref_ticks; + } + + if (BUTTON1_PRESSED(notif_value) && + is_btn_stable(current_ref_ticks, &btn1_debounce_tick_time)) { + LED_ASSERT(led_val, LED_MASK_BTN1); + on_btn1_event(&num_requested_subprocesses); + } else { + LED_DEASSERT(led_val, LED_MASK_BTN1); + btn1_debounce_tick_time = current_ref_ticks; + } + } + + rtos_gpio_port_out(gpio_ctx_t0, p_leds, led_val); + } +} + +#endif /* ON_TILE(0) */ + +static void hello_task(void *arg) +{ + rtos_printf("Hello task running from tile %d on core %d\n", THIS_XCORE_TILE, + portGET_CORE_ID()); + + for (;;) { + rtos_printf("Hello from tile %d\n", THIS_XCORE_TILE); + vTaskDelay(pdMS_TO_TICKS(1000)); + } +} + +static void tile_common_init(chanend_t c) +{ + platform_init(c); + +#if ON_TILE(0) + + resource_mutex = xSemaphoreCreateMutex(); +#if (TRC_USE_TRACEALYZER_RECORDER == 1) + vTraceSetSemaphoreName(resource_mutex, "Shared Resource"); + trc_main_state = xTraceRegisterString("Main State"); + trc_active_subprocesses = xTraceRegisterString("Active Subprocesses"); + trc_run_iteration = xTraceRegisterString("Run Iteration"); + trc_run_delta = xTraceRegisterString("Run Delta"); + trc_output = xTraceRegisterString("Output Signal"); +#endif + + xTaskCreate((TaskFunction_t)gpio_task, STRINGIFY(gpio_task), + RTOS_THREAD_STACK_SIZE(gpio_task), NULL, + configMAX_PRIORITIES - 1, &ctx_gpio_task); + xTaskCreate((TaskFunction_t)process_task, STRINGIFY(process_task), + RTOS_THREAD_STACK_SIZE(process_task), NULL, base_task_priority, + &ctx_process_task); + + /* Spawn subprocess tasks at one level higher priority than the previous */ + for (int i = 0; i < NUM_SUBPROCESS_TASKS; i++) { + char task_name[TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH]; + + snprintf(task_name, sizeof(task_name), "%s_%02d", + STRINGIFY(subprocess_task), i); + xTaskCreate((TaskFunction_t)subprocess_task, task_name, + RTOS_THREAD_STACK_SIZE(subprocess_task), + &ctx_subprocess_tasks[i], base_task_priority + i + 1, + &ctx_subprocess_tasks[i]); + } + +#endif /* ON_TILE(0) */ + + xTaskCreate((TaskFunction_t)hello_task, STRINGIFY(hello_task), + RTOS_THREAD_STACK_SIZE(hello_task), NULL, base_task_priority, + NULL); + + rtos_printf("Start scheduler on tile %d\n", THIS_XCORE_TILE); + vTaskStartScheduler(); +} + +/* + * Public Definitions + */ + +#if ON_TILE(0) +void main_tile0(chanend_t c0, chanend_t c1, chanend_t c2, chanend_t c3) +{ + (void)c0; + (void)c2; + (void)c3; +#if (USE_TRACE_MODE == TRACE_MODE_TRACEALYZER_STREAMING) + xTraceInitialize(); + xTraceEnable(TRC_START); +#endif + + tile_common_init(c1); +} +#endif + +#if ON_TILE(1) +void main_tile1(chanend_t c0, chanend_t c1, chanend_t c2, chanend_t c3) +{ + (void)c1; + (void)c2; + (void)c3; + + tile_common_init(c0); +} +#endif \ No newline at end of file diff --git a/examples/freertos/tracealyzer/src/trcConfig.h b/examples/freertos/tracealyzer/src/trcConfig.h new file mode 100644 index 000000000..1835823cc --- /dev/null +++ b/examples/freertos/tracealyzer/src/trcConfig.h @@ -0,0 +1,320 @@ +/* + * Trace Recorder for Tracealyzer v4.6.6 + * Copyright 2021 Percepio AB + * www.percepio.com + * + * SPDX-License-Identifier: Apache-2.0 + * + * Main configuration parameters for the trace recorder library. + * More settings can be found in trcStreamingConfig.h and trcSnapshotConfig.h. + */ + +#ifndef TRC_CONFIG_H +#define TRC_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/****************************************************************************** + * Include of processor header file + * + * Here you may need to include the header file for your processor. This is + * required at least for the ARM Cortex-M port, that uses the ARM CMSIS API. + * Try that in case of build problems. Otherwise, remove the #error line below. + *****************************************************************************/ +//#error "Trace Recorder: Please include your processor's header file here and remove this line." + +/** + * @def TRC_CFG_HARDWARE_PORT + * @brief Specify what hardware port to use (i.e., the "timestamping driver"). + * + * All ARM Cortex-M MCUs are supported by "TRC_HARDWARE_PORT_ARM_Cortex_M". + * This port uses the DWT cycle counter for Cortex-M3/M4/M7 devices, which is + * available on most such devices. In case your device don't have DWT support, + * you will get an error message opening the trace. In that case, you may + * force the recorder to use SysTick timestamping instead, using this define: + * + * #define TRC_CFG_ARM_CM_USE_SYSTICK + * + * For ARM Cortex-M0/M0+ devices, SysTick mode is used automatically. + * + * See trcHardwarePort.h for available ports and information on how to + * define your own port, if not already present. + */ +#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_XMOS_XCOREAI + +/** + * @def TRC_CFG_SCHEDULING_ONLY + * @brief Macro which should be defined as an integer value. + * + * If this setting is enabled (= 1), only scheduling events are recorded. + * If disabled (= 0), all events are recorded (unless filtered in other ways). + * + * Default value is 0 (= include additional events). + */ +#define TRC_CFG_SCHEDULING_ONLY 0 + +/** + * @def TRC_CFG_INCLUDE_MEMMANG_EVENTS + * @brief Macro which should be defined as either zero (0) or one (1). + * + * This controls if malloc and free calls should be traced. Set this to zero (0) + * to exclude malloc/free calls, or one (1) to include such events in the trace. + * + * Default value is 1. + */ +#define TRC_CFG_INCLUDE_MEMMANG_EVENTS 1 + +/** + * @def TRC_CFG_INCLUDE_USER_EVENTS + * @brief Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), all code related to User Events is excluded in order + * to reduce code size. Any attempts of storing User Events are then silently + * ignored. + * + * User Events are application-generated events, like "printf" but for the + * trace log, generated using vTracePrint and vTracePrintF. + * The formatting is done on host-side, by Tracealyzer. User Events are + * therefore much faster than a console printf and can often be used + * in timing critical code without problems. + * + * Note: In streaming mode, User Events are used to provide error messages + * and warnings from the recorder (in case of incorrect configuration) for + * display in Tracealyzer. Disabling user events will also disable these + * warnings. You can however still catch them by calling xTraceErrorGetLast + * or by putting breakpoints in xTraceError and xTraceWarning. + * + * Default value is 1. + */ +#define TRC_CFG_INCLUDE_USER_EVENTS 1 + +/** + * @def TRC_CFG_INCLUDE_ISR_TRACING + * @brief Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the code for recording Interrupt Service Routines is + * excluded, in order to reduce code size. This means that any calls to + * vTraceStoreISRBegin/vTraceStoreISREnd will be ignored. + * This does not completely disable ISR tracing, in cases where an ISR is + * calling a traced kernel service. These events will still be recorded and + * show up in anonymous ISR instances in Tracealyzer, with names such as + * "ISR sending to ". + * To disable such tracing, please refer to vTraceSetFilterGroup and + * vTraceSetFilterMask. + * + * Default value is 1. + * + * Note: tracing ISRs requires that you insert calls to vTraceStoreISRBegin + * and vTraceStoreISREnd in your interrupt handlers. + */ +#define TRC_CFG_INCLUDE_ISR_TRACING 1 + +/** + * @def TRC_CFG_INCLUDE_READY_EVENTS + * @brief Macro which should be defined as either zero (0) or one (1). + * + * If one (1), events are recorded when tasks enter scheduling state "ready". + * This allows Tracealyzer to show the initial pending time before tasks enter + * the execution state, and present accurate response times. + * If zero (0), "ready events" are not created, which allows for recording + * longer traces in the same amount of RAM. + * + * Default value is 1. + */ +#define TRC_CFG_INCLUDE_READY_EVENTS 1 + +/** + * @def TRC_CFG_INCLUDE_OSTICK_EVENTS + * @brief Macro which should be defined as either zero (0) or one (1). + * + * If this is one (1), events will be generated whenever the OS clock is + * increased. If zero (0), OS tick events are not generated, which allows for + * recording longer traces in the same amount of RAM. + * + * Default value is 1. + */ +#define TRC_CFG_INCLUDE_OSTICK_EVENTS 0 + +/** + * @def TRC_CFG_ENABLE_STACK_MONITOR + * @brief If enabled (1), the recorder periodically reports the unused stack space of + * all active tasks. + * The stack monitoring runs in the Tracealyzer Control task, TzCtrl. This task + * is always created by the recorder when in streaming mode. + * In snapshot mode, the TzCtrl task is only used for stack monitoring and is + * not created unless this is enabled. + */ +#define TRC_CFG_ENABLE_STACK_MONITOR 1 + +/** + * @def TRC_CFG_STACK_MONITOR_MAX_TASKS + * @brief Macro which should be defined as a non-zero integer value. + * + * This controls how many tasks that can be monitored by the stack monitor. + * If this is too small, some tasks will be excluded and a warning is shown. + * + * Default value is 10. + */ +#define TRC_CFG_STACK_MONITOR_MAX_TASKS 200 + +/** + * @def TRC_CFG_STACK_MONITOR_MAX_REPORTS + * @brief Macro which should be defined as a non-zero integer value. + * + * This defines how many tasks that will be subject to stack usage analysis for + * each execution of the Tracealyzer Control task (TzCtrl). Note that the stack + * monitoring cycles between the tasks, so this does not affect WHICH tasks that + * are monitored, but HOW OFTEN each task stack is analyzed. + * + * This setting can be combined with TRC_CFG_CTRL_TASK_DELAY to tune the + * frequency of the stack monitoring. This is motivated since the stack analysis + * can take some time to execute. + * However, note that the stack analysis runs in a separate task (TzCtrl) that + * can be executed on low priority. This way, you can avoid that the stack + * analysis disturbs any time-sensitive tasks. + * + * Default value is 1. + */ +#define TRC_CFG_STACK_MONITOR_MAX_REPORTS 1 + +/** + * @def TRC_CFG_CTRL_TASK_PRIORITY + * @brief The scheduling priority of the Tracealyzer Control (TzCtrl) task. + * + * In streaming mode, TzCtrl is used to receive start/stop commands from + * Tracealyzer and in some cases also to transmit the trace data (for stream + * ports that uses the internal buffer, like TCP/IP). For such stream ports, + * make sure the TzCtrl priority is high enough to ensure reliable periodic + * execution and transfer of the data, but low enough to avoid disturbing any + * time-sensitive functions. + * + * In Snapshot mode, TzCtrl is only used for the stack usage monitoring and is + * not created if stack monitoring is disabled. TRC_CFG_CTRL_TASK_PRIORITY should + * be low, to avoid disturbing any time-sensitive tasks. + */ +#define TRC_CFG_CTRL_TASK_PRIORITY 1 + +/** + * @def TRC_CFG_CTRL_TASK_DELAY + * @brief The delay between loops of the TzCtrl task (see TRC_CFG_CTRL_TASK_PRIORITY), + * which affects the frequency of the stack monitoring. + * + * In streaming mode, this also affects the trace data transfer if you are using + * a stream port leveraging the internal buffer (like TCP/IP). A shorter delay + * increases the CPU load of TzCtrl somewhat, but may improve the performance of + * of the trace streaming, especially if the trace buffer is small. + */ +#define TRC_CFG_CTRL_TASK_DELAY 100 + +/** + * @def TRC_CFG_CTRL_TASK_STACK_SIZE + * @brief The stack size of the Tracealyzer Control (TzCtrl) task. + * See TRC_CFG_CTRL_TASK_PRIORITY for further information about TzCtrl. + */ +#define TRC_CFG_CTRL_TASK_STACK_SIZE 1024 + +/** + * @def TRC_CFG_RECORDER_BUFFER_ALLOCATION + * @brief Specifies how the recorder buffer is allocated (also in case of streaming, in + * port using the recorder's internal temporary buffer) + * + * Values: + * TRC_RECORDER_BUFFER_ALLOCATION_STATIC - Static allocation (internal) + * TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC - Malloc in vTraceEnable + * TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM - Use vTraceSetRecorderDataBuffer + * + * Static and dynamic mode does the allocation for you, either in compile time + * (static) or in runtime (malloc). + * The custom mode allows you to control how and where the allocation is made, + * for details see TRC_ALLOC_CUSTOM_BUFFER and vTraceSetRecorderDataBuffer(). + */ +#define TRC_CFG_RECORDER_BUFFER_ALLOCATION TRC_RECORDER_BUFFER_ALLOCATION_STATIC + +/** + * @def TRC_CFG_MAX_ISR_NESTING + * @brief Defines how many levels of interrupt nesting the recorder can handle, in + * case multiple ISRs are traced and ISR nesting is possible. If this + * is exceeded, the particular ISR will not be traced and the recorder then + * logs an error message. This setting is used to allocate an internal stack + * for keeping track of the previous execution context (4 byte per entry). + * + * This value must be a non-zero positive constant, at least 1. + * + * Default value: 8 + */ +#define TRC_CFG_MAX_ISR_NESTING 8 + +/** + * @def TRC_CFG_ISR_TAILCHAINING_THRESHOLD + * @brief Macro which should be defined as an integer value. + * + * If tracing multiple ISRs, this setting allows for accurate display of the + * context-switching also in cases when the ISRs execute in direct sequence. + * + * vTraceStoreISREnd normally assumes that the ISR returns to the previous + * context, i.e., a task or a preempted ISR. But if another traced ISR + * executes in direct sequence, Tracealyzer may incorrectly display a minimal + * fragment of the previous context in between the ISRs. + * + * By using TRC_CFG_ISR_TAILCHAINING_THRESHOLD you can avoid this. This is + * however a threshold value that must be measured for your specific setup. + * See http://percepio.com/2014/03/21/isr_tailchaining_threshold/ + * + * The default setting is 0, meaning "disabled" and that you may get an + * extra fragments of the previous context in between tail-chained ISRs. + * + * Note: This setting has separate definitions in trcSnapshotConfig.h and + * trcStreamingConfig.h, since it is affected by the recorder mode. + */ +#define TRC_CFG_ISR_TAILCHAINING_THRESHOLD 0 + +/** + * @def TRC_CFG_RECORDER_DATA_INIT + * @brief Macro which states wether the recorder data should have an initial value. + * + * In very specific cases where traced objects are created before main(), + * the recorder will need to be started even before that. In these cases, + * the recorder data would be initialized by vTraceEnable(TRC_INIT) but could + * then later be overwritten by the initialization value. + * If this is an issue for you, set TRC_CFG_RECORDER_DATA_INIT to 0. + * The following code can then be used before any traced objects are created: + * + * extern uint32_t RecorderEnabled; + * RecorderEnabled = 0; + * xTraceInitialize(); + * + * After the clocks are properly initialized, use vTraceEnable(...) to start + * the tracing. + * + * Default value is 1. + */ +#define TRC_CFG_RECORDER_DATA_INIT 1 + +/** + * @def TRC_CFG_RECORDER_DATA_ATTRIBUTE + * @brief When setting TRC_CFG_RECORDER_DATA_INIT to 0, you might also need to make + * sure certain recorder data is placed in a specific RAM section to avoid being + * zeroed out after initialization. Define TRC_CFG_RECORDER_DATA_ATTRIBUTE as + * that attribute. + * + * Example: + * #define TRC_CFG_RECORDER_DATA_ATTRIBUTE __attribute__((section(".bss.trace_recorder_data"))) + * + * Default value is empty. + */ +#define TRC_CFG_RECORDER_DATA_ATTRIBUTE + +/** + * @def TRC_CFG_USE_TRACE_ASSERT + * @brief Enable or disable debug asserts. Information regarding any assert that is + * triggered will be in trcAssert.c. + */ +#define TRC_CFG_USE_TRACE_ASSERT 0 + +#ifdef __cplusplus +} +#endif + +#endif /* _TRC_CONFIG_H */ diff --git a/examples/freertos/tracealyzer/src/trcKernelPortConfig.h b/examples/freertos/tracealyzer/src/trcKernelPortConfig.h new file mode 100644 index 000000000..243d59efc --- /dev/null +++ b/examples/freertos/tracealyzer/src/trcKernelPortConfig.h @@ -0,0 +1,116 @@ +/* + * Trace Recorder for Tracealyzer v4.6.6 + * Copyright 2021 Percepio AB + * www.percepio.com + * + * SPDX-License-Identifier: Apache-2.0 + * + * Configuration parameters for the kernel port. + * More settings can be found in trcKernelPortStreamingConfig.h and + * trcKernelPortSnapshotConfig.h. + */ + +#ifndef TRC_KERNEL_PORT_CONFIG_H +#define TRC_KERNEL_PORT_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @def TRC_CFG_RECORDER_MODE + * @brief Specify what recording mode to use. Snapshot means that the data is saved in + * an internal RAM buffer, for later upload. Streaming means that the data is + * transferred continuously to the host PC. + * + * For more information, see http://percepio.com/2016/10/05/rtos-tracing/ + * and the Tracealyzer User Manual. + * + * Values: + * TRC_RECORDER_MODE_SNAPSHOT + * TRC_RECORDER_MODE_STREAMING + */ +#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_STREAMING + +/** + * @def TRC_CFG_FREERTOS_VERSION + * @brief Specify what version of FreeRTOS that is used (don't change unless using the + * trace recorder library with an older version of FreeRTOS). + * + * TRC_FREERTOS_VERSION_7_3_X If using FreeRTOS v7.3.X + * TRC_FREERTOS_VERSION_7_4_X If using FreeRTOS v7.4.X + * TRC_FREERTOS_VERSION_7_5_X If using FreeRTOS v7.5.X + * TRC_FREERTOS_VERSION_7_6_X If using FreeRTOS v7.6.X + * TRC_FREERTOS_VERSION_8_X_X If using FreeRTOS v8.X.X + * TRC_FREERTOS_VERSION_9_0_0 If using FreeRTOS v9.0.0 + * TRC_FREERTOS_VERSION_9_0_1 If using FreeRTOS v9.0.1 + * TRC_FREERTOS_VERSION_9_0_2 If using FreeRTOS v9.0.2 + * TRC_FREERTOS_VERSION_10_0_0 If using FreeRTOS v10.0.0 + * TRC_FREERTOS_VERSION_10_0_1 If using FreeRTOS v10.0.1 + * TRC_FREERTOS_VERSION_10_1_0 If using FreeRTOS v10.1.0 + * TRC_FREERTOS_VERSION_10_1_1 If using FreeRTOS v10.1.1 + * TRC_FREERTOS_VERSION_10_2_0 If using FreeRTOS v10.2.0 + * TRC_FREERTOS_VERSION_10_2_1 If using FreeRTOS v10.2.1 + * TRC_FREERTOS_VERSION_10_3_0 If using FreeRTOS v10.3.0 + * TRC_FREERTOS_VERSION_10_3_1 If using FreeRTOS v10.3.1 + * TRC_FREERTOS_VERSION_10_4_0 If using FreeRTOS v10.4.0 + * TRC_FREERTOS_VERSION_10_4_1 If using FreeRTOS v10.4.1 or later + */ +#define TRC_CFG_FREERTOS_VERSION TRC_FREERTOS_VERSION_10_4_1 + +/** + * @def TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS + * @brief Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any "event group" events. + * + * Default value is 0 (excluded) since dependent on event_groups.c + */ +#define TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS 1 + +/** + * @def TRC_CFG_INCLUDE_TIMER_EVENTS + * @brief Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any Timer events. + * + * Default value is 0 since dependent on timers.c + */ +#define TRC_CFG_INCLUDE_TIMER_EVENTS 1 + +/** + * @def TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS + * @brief Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any "pending function call" + * events, such as xTimerPendFunctionCall(). + * + * Default value is 0 since dependent on timers.c + */ +#define TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS 1 + +/** + * @def TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS + * @brief Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any stream buffer or message + * buffer events. + * + * Default value is 0 since dependent on stream_buffer.c (new in FreeRTOS v10) + */ +#define TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS 1 + +/** + * @def TRC_CFG_ACKNOWLEDGE_QUEUE_SET_SEND + * @brief When using FreeRTOS v10.3.0 or v10.3.1, please make sure that the trace + * point in prvNotifyQueueSetContainer() in queue.c is renamed from + * traceQUEUE_SEND to traceQUEUE_SET_SEND in order to tell them apart from + * other traceQUEUE_SEND trace points. Then set this to TRC_ACKNOWLEDGED. + */ +#define TRC_CFG_ACKNOWLEDGE_QUEUE_SET_SEND 0 /* TRC_ACKNOWLEDGED */ + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_KERNEL_PORT_CONFIG_H */ diff --git a/examples/freertos/tracealyzer/src/trcKernelPortStreamingConfig.h b/examples/freertos/tracealyzer/src/trcKernelPortStreamingConfig.h new file mode 100644 index 000000000..9fa4a8d34 --- /dev/null +++ b/examples/freertos/tracealyzer/src/trcKernelPortStreamingConfig.h @@ -0,0 +1,24 @@ +/* + * Trace Recorder for Tracealyzer v4.6.6 + * Copyright 2021 Percepio AB + * www.percepio.com + * + * SPDX-License-Identifier: Apache-2.0 + * + * Kernel port configuration parameters for streaming mode. + */ + +#ifndef TRC_KERNEL_PORT_STREAMING_CONFIG_H +#define TRC_KERNEL_PORT_STREAMING_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Nothing yet */ + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_KERNEL_PORT_STREAMING_CONFIG_H */ diff --git a/examples/freertos/tracealyzer/src/trcStreamPortConfig.h b/examples/freertos/tracealyzer/src/trcStreamPortConfig.h new file mode 100644 index 000000000..dba2eed49 --- /dev/null +++ b/examples/freertos/tracealyzer/src/trcStreamPortConfig.h @@ -0,0 +1,35 @@ +/* + * Trace Recorder for Tracealyzer v4.6.6 + * Copyright 2021 Percepio AB + * www.percepio.com + * + * SPDX-License-Identifier: Apache-2.0 + * + * The configuration for trace streaming ("stream ports"). + */ + +#ifndef TRC_STREAM_PORT_CONFIG_H +#define TRC_STREAM_PORT_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* This define will determine whether to use the internal buffer or not. +If file writing creates additional trace events (i.e. it uses semaphores or mutexes), +then the internal buffer must be enabled to avoid infinite recursion. */ +#define TRC_CFG_STREAM_PORT_USE_INTERNAL_BUFFER 0 + +/** +* @def TRC_CFG_INTERNAL_BUFFER_SIZE +* +* @brief Configures the size of the internal buffer if used. +* is enabled. +*/ +#define TRC_CFG_STREAM_PORT_INTERNAL_BUFFER_SIZE 35000 + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_STREAM_PORT_CONFIG_H */ diff --git a/examples/freertos/tracealyzer/src/trcStreamingConfig.h b/examples/freertos/tracealyzer/src/trcStreamingConfig.h new file mode 100644 index 000000000..7e65075ad --- /dev/null +++ b/examples/freertos/tracealyzer/src/trcStreamingConfig.h @@ -0,0 +1,51 @@ +/* + * Trace Recorder for Tracealyzer v4.6.6 + * Copyright 2021 Percepio AB + * www.percepio.com + * + * SPDX-License-Identifier: Apache-2.0 + * + * Configuration parameters for the trace recorder library in streaming mode. + * Read more at http://percepio.com/2016/10/05/rtos-tracing/ + */ + +#ifndef TRC_STREAMING_CONFIG_H +#define TRC_STREAMING_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @def TRC_CFG_ENTRY_SLOTS + * @brief The maximum number of objects and symbols that can be stored. This includes: + * - Task names + * - Named ISRs (vTraceSetISRProperties) + * - Named kernel objects (vTraceStoreKernelObjectName) + * - User event channels (xTraceStringRegister) + * + * If this value is too small, not all symbol names will be stored and the + * trace display will be affected. In that case, there will be warnings + * (as User Events) from TzCtrl task, that monitors this. + */ +#define TRC_CFG_ENTRY_SLOTS 250 + +/** + * @def TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH + * @brief The maximum length of symbol names, including: + * - Task names + * - Named ISRs (vTraceSetISRProperties) + * - Named kernel objects (vTraceStoreKernelObjectName) + * - User event channel names (xTraceStringRegister) + * + * If longer symbol names are used, they will be truncated by the recorder, + * which will affect the trace display. In that case, there will be warnings + * (as User Events) from TzCtrl task, that monitors this. + */ +#define TRC_CFG_ENTRY_SYMBOL_MAX_LENGTH 32 + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_STREAMING_CONFIG_H */ diff --git a/examples/freertos/tracealyzer/tracealyzer.cmake b/examples/freertos/tracealyzer/tracealyzer.cmake new file mode 100644 index 000000000..eba00bf34 --- /dev/null +++ b/examples/freertos/tracealyzer/tracealyzer.cmake @@ -0,0 +1,76 @@ +#********************** +# Gather Sources +#********************** +file(GLOB_RECURSE APP_SOURCES ${CMAKE_CURRENT_LIST_DIR}/src/*.c) +set(APP_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src) + +#********************** +# Flags +#********************** +set(APP_COMPILER_FLAGS + -Os + -g + -report + -fxscope + -mcmodel=large + -Wno-xcore-fptrgroup + ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn +) + +# See xcore_trace.h for valid USE_TRACE_MODE values. +set(APP_COMPILE_DEFINITIONS + USE_TRACE_MODE=TRACE_MODE_TRACEALYZER_STREAMING + DEBUG_PRINT_ENABLE=1 + PLATFORM_USES_TILE_0=1 + PLATFORM_USES_TILE_1=1 + XE_BASE_TILE=0 + XUD_CORE_CLOCK=600 +) + +set(APP_LINK_OPTIONS + -report + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn + ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope +) + +set(APP_LINK_LIBRARIES + rtos::bsp_config::xcore_ai_explorer + rtos::drivers::trace +) + +#********************** +# Tile Targets +#********************** +set(TARGET_NAME tile0_example_freertos_tracealyzer) +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 ${APP_COMPILE_DEFINITIONS} THIS_XCORE_TILE=0) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +set(TARGET_NAME tile1_example_freertos_tracealyzer) +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 ${APP_COMPILE_DEFINITIONS} THIS_XCORE_TILE=1) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS} ) +unset(TARGET_NAME) + +#********************** +# Merge binaries +#********************** +merge_binaries(example_freertos_tracealyzer tile0_example_freertos_tracealyzer tile1_example_freertos_tracealyzer 1) + +#********************** +# Create run and debug targets +#********************** +create_run_xscope_to_file_target(example_freertos_tracealyzer freertos_trace) +create_run_target(example_freertos_tracealyzer) +create_debug_target(example_freertos_tracealyzer) +create_install_target(example_freertos_tracealyzer) diff --git a/examples/freertos/usb/src/dfu_demo_support.c b/examples/freertos/usb/src/dfu_demo_support.c index c5bd0d2a5..c0f806eb1 100644 --- a/examples/freertos/usb/src/dfu_demo_support.c +++ b/examples/freertos/usb/src/dfu_demo_support.c @@ -28,7 +28,7 @@ int check_dfu_mode(void) (uint8_t*)&mode, (unsigned)(MODE_ADDR), (size_t)sizeof(int)); - // rtos_printf("Mode is %u\n", mode); + rtos_printf("Mode is %u\n", mode); if(mode == 0xffffffff) mode = 0; // uninitialized should be handled as RT return mode; } diff --git a/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/demo_main.c b/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/demo_main.c index 2f2f3ede6..3ceb0d717 100644 --- a/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/demo_main.c +++ b/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/demo_main.c @@ -130,101 +130,147 @@ void tud_resume_cb(void) } //--------------------------------------------------------------------+ -// Class callbacks +// 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; -bool tud_dfu_firmware_valid_check_cb() + +// 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. +uint32_t tud_dfu_get_timeout_cb(uint8_t alt, uint8_t state) { - uint8_t dummy; - rtos_printf("Pass firmware validity check addr 0x%x size %u\n", dn_base_addr, total_len); - set_rt_mode(); - boot_image_read(bim_ctx_ptr->app_data, 0, &dummy, 1); // dummy read to ensure flash writes have completed - reboot(); - return true; + if ( state == DFU_DNBUSY ) + { + return 10; /* 10 ms */ + } + else if (state == DFU_MANIFEST) + { + // since we don't buffer entire image and do any flashing in manifest stage + return 0; + } + + return 0; } -void tud_dfu_req_dnload_data_cb(uint16_t wBlockNum, uint8_t* data, uint16_t length) +// Invoked when received DFU_DNLOAD (wLength>0) following by DFU_GETSTATUS (state=DFU_DNBUSY) requests +// This callback could be returned before flashing op is complete (async). +// 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("Block[%u] Len[%u] Buffer\n", wBlockNum, length); - - if (dn_base_addr == 0) - { - uint32_t addr = 0; - total_len = 0; - int tmp = boot_image_locate_available_spot(bim_ctx_ptr, &addr, &bytes_avail); - if(tmp == -1) - { - boot_image_t* imgptr = NULL; - imgptr = boot_image_get_last_image(bim_ctx_ptr); - addr = imgptr->startAddress; - bytes_avail = bim_ctx_ptr->boot_partition_size - addr; - } - rtos_printf("Using addr 0x%x\nsize %u\n", addr, bytes_avail); - dn_base_addr = addr; - } - - if(length > 0) - { - unsigned cur_addr = dn_base_addr + (wBlockNum * bim_ctx_ptr->page_size); - if((bytes_avail - total_len) >= length) + (void) alt; + rtos_printf("Block[%u] Len[%u] Buffer\n", block_num, length); + if (dn_base_addr == 0) { - // rtos_printf("write %d at 0x%x\n", length, cur_addr); - boot_image_write(bim_ctx_ptr->app_data, cur_addr, data, length); - total_len += length; + uint32_t addr = 0; + total_len = 0; + int tmp = boot_image_locate_available_spot(bim_ctx_ptr, &addr, &bytes_avail); + if(tmp == -1) + { + boot_image_t* imgptr = NULL; + imgptr = boot_image_get_last_image(bim_ctx_ptr); + addr = imgptr->startAddress; + bytes_avail = bim_ctx_ptr->boot_partition_size - addr; + } + rtos_printf("Using addr 0x%x\nsize %u\n", addr, bytes_avail); + dn_base_addr = addr; + } - tud_dfu_dnload_complete(); - } else { - rtos_printf("Insufficient space\n"); + if(length > 0) + { + unsigned cur_addr = dn_base_addr + (block_num * bim_ctx_ptr->page_size); + if((bytes_avail - total_len) >= length) + { + // rtos_printf("write %d at 0x%x\n", length, cur_addr); + boot_image_write(bim_ctx_ptr->app_data, cur_addr, data, length); + total_len += length; + } else { + rtos_printf("Insufficient space\n"); + } } - } } -bool tud_dfu_device_data_done_check_cb() +// Invoked when download process is complete, received DFU_DNLOAD (wLength=0) following by DFU_GETSTATUS (state=Manifest) +// Application can do checksum, or actual flashing if buffered entire image previously. +// Once finished flashing, application must call tud_dfu_finish_flashing() +void tud_dfu_manifest_cb(uint8_t alt) { - rtos_printf("Dummy device data done check... Returning true\n"); - return true; -} + (void) alt; + rtos_printf("Download completed, enter manifestation\n"); + uint8_t dummy; -void tud_dfu_abort_cb() -{ - rtos_printf("Host Aborted transfer\n"); + rtos_printf("Pass firmware validity check addr 0x%x size %u\n", dn_base_addr, total_len); + set_rt_mode(); + boot_image_read(bim_ctx_ptr->app_data, 0, &dummy, 1); // dummy read to ensure flash writes have completed + reboot(); + + /* TODO actually verify */ + // tud_dfu_finish_flashing(DFU_STATUS_ERR_VERIFY); + // 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); } -uint16_t tud_dfu_req_upload_data_cb(uint16_t block_num, uint8_t* data, uint16_t length) +// Invoked when received DFU_UPLOAD request +// Application must populate data with up to length bytes and +// 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) { - memset(data, 0x00, length); - uint32_t addr = block_num * FLASH_PAGE_SIZE; - uint32_t endaddr; + (void) alt; + + memset(data, 0x00, length); + uint32_t addr = block_num * FLASH_PAGE_SIZE; + uint32_t endaddr; #if 0 - // Test code which will just read out all of flash rather than a specific image - endaddr = 0x800000; + // Test code which will just read out all of flash rather than a specific image + endaddr = 0x800000; #else - boot_image_t* imgptr = NULL; - imgptr = boot_image_get_last_image(bim_ctx_ptr); - addr += imgptr->startAddress; - endaddr = imgptr->startAddress + imgptr->size; + boot_image_t* imgptr = NULL; + imgptr = boot_image_get_last_image(bim_ctx_ptr); + addr += imgptr->startAddress; + endaddr = imgptr->startAddress + imgptr->size; #endif - return (addr >= endaddr) ? 0 : (uint16_t)boot_image_read(bim_ctx_ptr->app_data, addr, data, length); + return (addr >= endaddr) ? 0 : (uint16_t)boot_image_read(bim_ctx_ptr->app_data, addr, data, length); } -static void reboot(void) +// Invoked when the Host has terminated a download or upload transfer +void tud_dfu_abort_cb(uint8_t alt) { - 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) {;} + (void) alt; + uint8_t dummy; + rtos_printf("Host Aborted transfer. Reboot to RT\n"); + set_rt_mode(); + boot_image_read(bim_ctx_ptr->app_data, 0, &dummy, 1); // dummy read to ensure flash writes have completed + reboot(); +} + +// Invoked when a DFU_DETACH request is received +void tud_dfu_detach_cb(void) +{ + rtos_printf("Host detach, reboot\n"); + set_rt_mode(); + reboot(); } void tud_dfu_runtime_reboot_to_dfu_cb(void) { + rtos_printf("Host detach, reboot\n"); set_dfu_mode(); 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) {;} +} + //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ diff --git a/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/tusb_config.h b/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/tusb_config.h index 92648f3a4..319b2072b 100644 --- a/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/tusb_config.h +++ b/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/tusb_config.h @@ -76,12 +76,14 @@ #define CFG_TUD_ENDPOINT0_SIZE 64 #endif -#define CFG_TUD_DFU_TRANSFER_BUFFER_SIZE 4096 +// #define CFG_TUD_DFU_TRANSFER_BUFFER_SIZE 4096 +#define CFG_TUD_DFU_XFER_BUFSIZE ( OPT_MODE_HIGH_SPEED ? 512 : 64 ) //------------- CLASS -------------// -#define CFG_TUD_DFU_RUNTIME 1 -#define CFG_TUD_DFU_MODE 1 +// #define CFG_TUD_DFU_RUNTIME 1 +// #define CFG_TUD_DFU_MODE 1 +#define CFG_TUD_DFU 1 #ifdef __cplusplus } diff --git a/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/usb_descriptors.c b/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/usb_descriptors.c index 6e0f0e31d..2e153bbab 100644 --- a/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/usb_descriptors.c +++ b/examples/freertos/usb/tinyusb_demos/dfu_runtime/src/usb_descriptors.c @@ -119,11 +119,9 @@ enum ITF1_NUM_TOTAL }; -#define CONFIG_1_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_DFU_MODE_DESC_LEN ) +#define CONFIG_1_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_DFU_DESC_LEN(1) ) -#define FUNC_ATTRS (DFU_FUNC_ATTR_CAN_UPLOAD_BITMASK | DFU_FUNC_ATTR_CAN_DOWNLOAD_BITMASK) -// #define FUNC_ATTRS (DFU_FUNC_ATTR_WILL_DETACH_BITMASK | DFU_FUNC_ATTR_CAN_UPLOAD_BITMASK | DFU_FUNC_ATTR_CAN_DOWNLOAD_BITMASK) -// #define FUNC_ATTRS 0x0d // original +#define FUNC_ATTRS (DFU_ATTR_CAN_UPLOAD | DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_MANIFESTATION_TOLERANT) uint8_t const desc_configuration_rt[] = { @@ -131,7 +129,7 @@ uint8_t const desc_configuration_rt[] = TUD_CONFIG_DESCRIPTOR(1, ITF0_NUM_TOTAL, 0, CONFIG_0_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), // Interface number, string index, attributes, detach timeout, transfer size */ - TUD_DFU_RT_DESCRIPTOR(ITF0_NUM_DFU_RT, 4, FUNC_ATTRS, 1000, CFG_TUD_DFU_TRANSFER_BUFFER_SIZE), + TUD_DFU_RT_DESCRIPTOR(ITF0_NUM_DFU_RT, 4, FUNC_ATTRS, 1000, CFG_TUD_DFU_XFER_BUFSIZE), }; uint8_t const desc_configuration_mode[] = @@ -140,7 +138,7 @@ uint8_t const desc_configuration_mode[] = TUD_CONFIG_DESCRIPTOR(1, ITF1_NUM_TOTAL, 0, CONFIG_1_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), // Interface number, string index, attributes, detach timeout, transfer size */ - TUD_DFU_MODE_DESCRIPTOR(ITF1_NUM_DFU_MODE, 0, FUNC_ATTRS, 1000, CFG_TUD_DFU_TRANSFER_BUFFER_SIZE), + TUD_DFU_DESCRIPTOR(ITF1_NUM_DFU_MODE, 1, 5, FUNC_ATTRS, 1000, CFG_TUD_DFU_XFER_BUFSIZE), }; // Invoked when received GET CONFIGURATION DESCRIPTOR @@ -149,7 +147,9 @@ uint8_t const desc_configuration_mode[] = uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { (void) index; // for multiple configurations - return check_dfu_mode() ? desc_configuration_rt : desc_configuration_mode; + return desc_configuration_mode; + /* TODO tmp always mode for now*/ + // return check_dfu_mode() ? desc_configuration_rt : desc_configuration_mode; } //--------------------------------------------------------------------+ @@ -164,6 +164,7 @@ char const* string_desc_arr [] = "TinyUSB Device", // 2: Product "123456", // 3: Serials, should use chip ID "TinyUSB DFU runtime", // 4: DFU runtime + "TinyUSB DFU FLASH", // 5: DFU device }; static uint16_t _desc_str[32]; diff --git a/examples/freertos/usb/usb.cmake b/examples/freertos/usb/usb.cmake index b6fbd19e5..15d124543 100644 --- a/examples/freertos/usb/usb.cmake +++ b/examples/freertos/usb/usb.cmake @@ -211,48 +211,47 @@ create_run_target(example_freertos_usb_tusb_demo_dfu) create_debug_target(example_freertos_usb_tusb_demo_dfu) -# Incomplete pending xcore tools updates #********************** # DFU Runtime Tile Targets #********************** -# file(GLOB_RECURSE DEMO_SOURCES ${CMAKE_CURRENT_LIST_DIR}/tinyusb_demos/dfu_runtime/src/*.c ) -# set(DEMO_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/tinyusb_demos/dfu_runtime/src/) -# set(DEMO_COMPILE_DEFINITIONS BOARD_DEVICE_RHPORT_SPEED=OPT_MODE_HIGH_SPEED -# DFU_DEMO=1 -# ) -# set(TARGET_NAME tile0_example_freertos_usb_tusb_demo_dfu_runtime) -# add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL) -# target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES} ${DEMO_SOURCES}) -# target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES} ${DEMO_INCLUDES}) -# target_compile_definitions(${TARGET_NAME} PUBLIC ${APP_COMPILE_DEFINITIONS} ${DEMO_COMPILE_DEFINITIONS} THIS_XCORE_TILE=0) -# target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) -# target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) -# target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) -# unset(TARGET_NAME) -# -# set(TARGET_NAME tile1_example_freertos_usb_tusb_demo_dfu_runtime) -# add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL) -# target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES} ${DEMO_SOURCES}) -# target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES} ${DEMO_INCLUDES}) -# target_compile_definitions(${TARGET_NAME} PUBLIC ${APP_COMPILE_DEFINITIONS} ${DEMO_COMPILE_DEFINITIONS} THIS_XCORE_TILE=1) -# target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) -# target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) -# target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) -# unset(TARGET_NAME) -# unset(DEMO_SOURCES) -# unset(DEMO_INCLUDES) -# unset(DEMO_COMPILE_DEFINITIONS) -# -# #********************** -# # Merge binaries -# #********************** -# merge_binaries(example_freertos_usb_tusb_demo_dfu_runtime tile0_example_freertos_usb_tusb_demo_dfu_runtime tile1_example_freertos_usb_tusb_demo_dfu_runtime 1) -# -# #********************** -# # Create run and debug targets -# #********************** -# create_run_target(example_freertos_usb_tusb_demo_dfu_runtime) -# create_debug_target(example_freertos_usb_tusb_demo_dfu_runtime) +file(GLOB_RECURSE DEMO_SOURCES ${CMAKE_CURRENT_LIST_DIR}/tinyusb_demos/dfu_runtime/src/*.c ) +set(DEMO_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/tinyusb_demos/dfu_runtime/src/) +set(DEMO_COMPILE_DEFINITIONS BOARD_DEVICE_RHPORT_SPEED=OPT_MODE_HIGH_SPEED + DFU_DEMO=1 +) +set(TARGET_NAME tile0_example_freertos_usb_tusb_demo_dfu_runtime) +add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL) +target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES} ${DEMO_SOURCES}) +target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES} ${DEMO_INCLUDES}) +target_compile_definitions(${TARGET_NAME} PUBLIC ${APP_COMPILE_DEFINITIONS} ${DEMO_COMPILE_DEFINITIONS} THIS_XCORE_TILE=0) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +set(TARGET_NAME tile1_example_freertos_usb_tusb_demo_dfu_runtime) +add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL) +target_sources(${TARGET_NAME} PUBLIC ${APP_SOURCES} ${DEMO_SOURCES}) +target_include_directories(${TARGET_NAME} PUBLIC ${APP_INCLUDES} ${DEMO_INCLUDES}) +target_compile_definitions(${TARGET_NAME} PUBLIC ${APP_COMPILE_DEFINITIONS} ${DEMO_COMPILE_DEFINITIONS} THIS_XCORE_TILE=1) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS}) +unset(TARGET_NAME) +unset(DEMO_SOURCES) +unset(DEMO_INCLUDES) +unset(DEMO_COMPILE_DEFINITIONS) + +#********************** +# Merge binaries +#********************** +merge_binaries(example_freertos_usb_tusb_demo_dfu_runtime tile0_example_freertos_usb_tusb_demo_dfu_runtime tile1_example_freertos_usb_tusb_demo_dfu_runtime 1) + +#********************** +# Create run and debug targets +#********************** +create_run_target(example_freertos_usb_tusb_demo_dfu_runtime) +create_debug_target(example_freertos_usb_tusb_demo_dfu_runtime) #********************** diff --git a/examples/freertos/xlink/README.rst b/examples/freertos/xlink/README.rst new file mode 100644 index 000000000..1e3937475 --- /dev/null +++ b/examples/freertos/xlink/README.rst @@ -0,0 +1,153 @@ +##### +XLINK +##### + +This example application demonstrates the `AN01024 `_ application note in FreeRTOS on XCORE AI. + +.. note:: + + This example application required XTC Tools version 15.2.0 or newer. + +********************** +Preparing the hardware +********************** + +This example requires 2 XCORE-AI-EXPLORER boards, and a user provided device to act as an I2C slave. + +To setup the board for testing, the following connections must be made: + +.. list-table:: XCORE-AI-EXPLORER to XCORE-AI-EXPLORER Connections 2 Wire + :widths: 50 50 + :header-rows: 1 + :align: left + + * - BOARD 0 + - BOARD 1 + * - GND + - GND + * - X1D65 + - X1D66 + * - X1D66 + - X1D65 + * - X1D64 + - X1D67 + * - X1D67 + - X1D64 + * - X1D63 + - X1D68 + * - X1D68 + - X1D63 + * - X1D62 + - X1D69 + * - X1D69 + - X1D62 + * - X1D61 + - X1D70 + * - X1D70 + - X1D61 + +.. list-table:: XCORE-AI-EXPLORER to XCORE-AI-EXPLORER Connections 5 Wire Additions + :widths: 50 50 + :header-rows: 1 + :align: left + + * - BOARD 0 + - BOARD 1 + * - X1D63 + - X1D68 + * - X1D68 + - X1D63 + * - X1D62 + - X1D69 + * - X1D69 + - X1D62 + * - X1D61 + - X1D70 + * - X1D70 + - X1D61 + +.. list-table:: XCORE-AI-EXPLORER Board 0 to Host Connections + :widths: 50 50 + :header-rows: 1 + :align: left + + * - BOARD 0 + - Host + * - GND + - Host GND + * - SCL + - Host SCL + * - SDA + - Host SDA + +********************* +Building the firmware +********************* + +Run the following commands in the xcore_sdk root folder to build the firmware: + +.. tab:: Linux and Mac + + .. code-block:: console + + cmake -B build -DCMAKE_TOOLCHAIN_FILE=xmos_cmake_toolchain/xs3a.cmake + cd build + make example_freertos_xlink_both + +.. tab:: Windows + + .. code-block:: console + + cmake -G "NMake Makefiles" -B build -DCMAKE_TOOLCHAIN_FILE=xmos_cmake_toolchain/xs3a.cmake + cd build + nmake example_freertos_xlink_both + +******************** +Running the firmware +******************** + +This application requires example_freertos_xlink_0.xe to be run on BOARD 0, IE, the board with a host I2C connection. + +Use the following command to determine available device: + +.. code-block:: console + + xrun --list-devices + +From the xcore_sdk build folder run: + +.. code-block:: console + + xrun --id 0 example_freertos_xlink_0.xe + +In another console, from the xcore_sdk build folder run: + +.. code-block:: console + + xrun --id 1 example_freertos_xlink_1.xe + +BOARD 0 will send out status messages and communication details to slave address 0xC. + +The data will contain an ID, followed by a 4 byte payload. The payload is an int32, sent least significant byte first. + +Payloads match to ID per the table below: + +.. list-table:: XCORE-AI-EXPLORER to XCORE-AI-EXPLORER Connections 2 Wire + :widths: 50 50 + :header-rows: 1 + :align: left + + * - ID + - Payload + * - 0x01 + - RX state + * - 0x82 + - received data bytes in the last second + * - 0x83 + - received control tokens in the last second + * - 0x84 + - timeouts in the last second + +.. note:: + + Data rates are highly dependant on the electrical characteristics of the physical connection. Refer to `xCONNECT Architecture `_ for more information. \ No newline at end of file diff --git a/examples/freertos/xlink/XCORE-AI-EXPLORER.xn b/examples/freertos/xlink/XCORE-AI-EXPLORER.xn new file mode 100644 index 000000000..ac4754ef0 --- /dev/null +++ b/examples/freertos/xlink/XCORE-AI-EXPLORER.xn @@ -0,0 +1,131 @@ + + + Board + xcore.ai Explorer Kit + + + tileref tile[2] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/freertos/xlink/XCORE-AI-EXPLORER_tx.xn b/examples/freertos/xlink/XCORE-AI-EXPLORER_tx.xn new file mode 100644 index 000000000..4dde19f84 --- /dev/null +++ b/examples/freertos/xlink/XCORE-AI-EXPLORER_tx.xn @@ -0,0 +1,109 @@ + + + Board + xcore.ai Explorer Kit + + + tileref tile[2] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/freertos/xlink/bsp_config/CMakeLists.txt b/examples/freertos/xlink/bsp_config/CMakeLists.txt new file mode 100644 index 000000000..5d4d1417e --- /dev/null +++ b/examples/freertos/xlink/bsp_config/CMakeLists.txt @@ -0,0 +1,31 @@ +if(${CMAKE_SYSTEM_NAME} STREQUAL XCORE_XS3A) + ## Create Explorer Board 2V0 target + add_library(example_freertos_xlink_board_support_config_xcore_ai_explorer_2V0 INTERFACE) + target_sources(example_freertos_xlink_board_support_config_xcore_ai_explorer_2V0 + INTERFACE + XCORE-AI-EXPLORER_2V0/platform/driver_instances.c + XCORE-AI-EXPLORER_2V0/platform/platform_init.c + XCORE-AI-EXPLORER_2V0/platform/platform_start.c + ) + target_include_directories(example_freertos_xlink_board_support_config_xcore_ai_explorer_2V0 + INTERFACE + XCORE-AI-EXPLORER_2V0 + ) + target_link_libraries(example_freertos_xlink_board_support_config_xcore_ai_explorer_2V0 + INTERFACE + core::general + rtos::freertos + rtos::drivers::general + ) + target_compile_definitions(example_freertos_xlink_board_support_config_xcore_ai_explorer_2V0 + INTERFACE + XCOREAI_EXPLORER=1 + PLATFORM_SUPPORTS_TILE_0=1 + PLATFORM_SUPPORTS_TILE_1=1 + PLATFORM_SUPPORTS_TILE_2=0 + PLATFORM_SUPPORTS_TILE_3=0 + ) + + ## Create an alias + add_library(example::freertos::xlink::bsp_config::xcore_ai_explorer_2V0 ALIAS example_freertos_xlink_board_support_config_xcore_ai_explorer_2V0) +endif() diff --git a/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.c b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.c new file mode 100644 index 000000000..3518a2abc --- /dev/null +++ b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.c @@ -0,0 +1,16 @@ +// Copyright (c) 2021-2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#include "platform/driver_instances.h" + +static rtos_intertile_t intertile_ctx_s; +rtos_intertile_t *intertile_ctx = &intertile_ctx_s; + +static rtos_gpio_t gpio_ctx_t0_s; +rtos_gpio_t *gpio_ctx_t0 = &gpio_ctx_t0_s; + +static rtos_gpio_t gpio_ctx_t1_s; +rtos_gpio_t *gpio_ctx_t1 = &gpio_ctx_t1_s; + +static rtos_i2c_master_t i2c_master_ctx_s; +rtos_i2c_master_t *i2c_master_ctx = &i2c_master_ctx_s; diff --git a/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.h b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.h new file mode 100644 index 000000000..a31ca9e3e --- /dev/null +++ b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/driver_instances.h @@ -0,0 +1,32 @@ +// Copyright (c) 2021-2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#ifndef DRIVER_INSTANCES_H_ +#define DRIVER_INSTANCES_H_ + +#include "rtos_intertile.h" +#include "rtos_i2c_master.h" +#include "rtos_gpio.h" + +#define I2C_TILE_NO 0 + +/** TILE 0 Clock Blocks */ +// #define UNUSED_CLKBLK XS1_CLKBLK_1 +// #define UNUSED_CLKBLK XS1_CLKBLK_2 +// #define UNUSED_CLKBLK XS1_CLKBLK_3 +// #define UNUSED_CLKBLK XS1_CLKBLK_4 /* Reserved for lib_xud */ +// #define UNUSED_CLKBLK XS1_CLKBLK_5 /* Reserved for lib_xud */ + +/** TILE 1 Clock Blocks */ +// #define UNUSED_CLKBLK XS1_CLKBLK_1 +// #define UNUSED_CLKBLK XS1_CLKBLK_2 +// #define UNUSED_CLKBLK XS1_CLKBLK_3 +// #define UNUSED_CLKBLK XS1_CLKBLK_4 +// #define UNUSED_CLKBLK XS1_CLKBLK_5 + +extern rtos_intertile_t *intertile_ctx; +extern rtos_gpio_t *gpio_ctx_t0; +extern rtos_gpio_t *gpio_ctx_t1; +extern rtos_i2c_master_t *i2c_master_ctx; + +#endif /* DRIVER_INSTANCES_H_ */ diff --git a/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_conf.h b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_conf.h new file mode 100644 index 000000000..43e1f0366 --- /dev/null +++ b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_conf.h @@ -0,0 +1,62 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#ifndef PLATFORM_CONF_H_ +#define PLATFORM_CONF_H_ + +/* + * This file contains defaults to build a basic project targetting the + * XCORE-AI-EXPLORER board. Users may create their own app_conf.h to override + * any default settings. + * + * For a different soft tapeout design, it is recommended to create an entirely + * different board support package. + */ + +#if __has_include("app_conf.h") +#include "app_conf.h" +#endif /* __has_include("app_conf.h") */ + +/*****************************************/ +/* Intertile Communication Configuration */ +/*****************************************/ +#ifndef appconfI2C_MASTER_RPC_PORT +#define appconfI2C_MASTER_RPC_PORT 10 +#endif /* appconfI2C_MASTER_RPC_PORT */ + +#ifndef appconfI2C_MASTER_RPC_PRIORITY +#define appconfI2C_MASTER_RPC_PRIORITY (configMAX_PRIORITIES/2) +#endif /* appconfI2C_MASTER_RPC_PRIORITY */ + +#ifndef appconfGPIO_T0_RPC_PORT +#define appconfGPIO_T0_RPC_PORT 11 +#endif /* appconfGPIO_T0_RPC_PORT */ + +#ifndef appconfGPIO_T1_RPC_PORT +#define appconfGPIO_T1_RPC_PORT 12 +#endif /* appconfGPIO_T1_RPC_PORT */ + +#ifndef appconfGPIO_RPC_PRIORITY +#define appconfGPIO_RPC_PRIORITY (configMAX_PRIORITIES/2) +#endif /* appconfGPIO_RPC_PRIORITY */ + +/*****************************************/ +/* I/O and interrupt cores for Tile 0 */ +/*****************************************/ +#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 */ + +/*****************************************/ +/* I/O and interrupt cores for Tile 1 */ +/*****************************************/ + +/*****************************************/ +/* I/O Task Priorities */ +/*****************************************/ + +#endif /* PLATFORM_CONF_H_ */ diff --git a/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.c b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.c new file mode 100644 index 000000000..49cb2c250 --- /dev/null +++ b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.c @@ -0,0 +1,78 @@ +// Copyright (c) 2021-2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#include + +#include "platform_conf.h" +#include "platform/driver_instances.h" + +static void gpio_init(void) +{ + static rtos_driver_rpc_t gpio_rpc_config_t0; + static rtos_driver_rpc_t gpio_rpc_config_t1; + rtos_intertile_t *client_intertile_ctx[1] = {intertile_ctx}; + +#if ON_TILE(0) + rtos_gpio_init(gpio_ctx_t0); + + rtos_gpio_rpc_host_init( + gpio_ctx_t0, + &gpio_rpc_config_t0, + client_intertile_ctx, + 1); + + rtos_gpio_rpc_client_init( + gpio_ctx_t1, + &gpio_rpc_config_t1, + intertile_ctx); +#endif + +#if ON_TILE(1) + rtos_gpio_init(gpio_ctx_t1); + + rtos_gpio_rpc_client_init( + gpio_ctx_t0, + &gpio_rpc_config_t0, + intertile_ctx); + + rtos_gpio_rpc_host_init( + gpio_ctx_t1, + &gpio_rpc_config_t1, + client_intertile_ctx, + 1); +#endif +} + +static void i2c_init(void) +{ + static rtos_driver_rpc_t i2c_rpc_config; + +#if ON_TILE(I2C_TILE_NO) + rtos_intertile_t *client_intertile_ctx[1] = {intertile_ctx}; + rtos_i2c_master_init( + i2c_master_ctx, + PORT_I2C_SCL, 0, 0, + PORT_I2C_SDA, 0, 0, + 0, + 100); + + rtos_i2c_master_rpc_host_init( + i2c_master_ctx, + &i2c_rpc_config, + client_intertile_ctx, + 1); +#else + rtos_i2c_master_rpc_client_init( + i2c_master_ctx, + &i2c_rpc_config, + intertile_ctx); +#endif +} + +void platform_init(chanend_t other_tile_c) +{ + rtos_intertile_init(intertile_ctx, other_tile_c); + + gpio_init(); + i2c_init(); +} diff --git a/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.h b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.h new file mode 100644 index 000000000..98725556d --- /dev/null +++ b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_init.h @@ -0,0 +1,12 @@ +// Copyright (c) 2021 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#ifndef PLATFORM_INIT_H_ +#define PLATFORM_INIT_H_ + +#include + +void platform_init(chanend_t other_tile_c); +void platform_start(void); + +#endif /* PLATFORM_INIT_H_ */ diff --git a/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_start.c b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_start.c new file mode 100644 index 000000000..7403ce776 --- /dev/null +++ b/examples/freertos/xlink/bsp_config/XCORE-AI-EXPLORER_2V0/platform/platform_start.c @@ -0,0 +1,36 @@ +// Copyright (c) 2021-2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#include + +#include "platform_conf.h" +#include "platform/driver_instances.h" + +static void gpio_start(void) +{ + rtos_gpio_rpc_config(gpio_ctx_t0, appconfGPIO_T0_RPC_PORT, appconfGPIO_RPC_PRIORITY); + rtos_gpio_rpc_config(gpio_ctx_t1, appconfGPIO_T1_RPC_PORT, appconfGPIO_RPC_PRIORITY); + +#if ON_TILE(0) + rtos_gpio_start(gpio_ctx_t0); +#endif +#if ON_TILE(1) + rtos_gpio_start(gpio_ctx_t1); +#endif +} + +static void i2c_start(void) +{ + 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 +} + +void platform_start(void) +{ + rtos_intertile_start(intertile_ctx); + + gpio_start(); + i2c_start(); +} diff --git a/examples/freertos/xlink/src/FreeRTOSConfig.h b/examples/freertos/xlink/src/FreeRTOSConfig.h new file mode 100644 index 000000000..b954bd30e --- /dev/null +++ b/examples/freertos/xlink/src/FreeRTOSConfig.h @@ -0,0 +1,118 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/* Here is a good place to include header files that are required across +your application. */ +#include "platform.h" + +/* + * TODO remove this. Just a hack to prevent the i2s task from calling vTaskSuspendAll(). Not a good solution. + * the i2s task should probably not be using a FreeRTOS stream buffer. + */ +#define sbRECEIVE_COMPLETED( pxStreamBuffer ) + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 0 +#define configCPU_CLOCK_HZ 100000000 +#define configNUM_CORES 5 +#define configTICK_RATE_HZ 1000 +#define configMAX_PRIORITIES 32 +#define configRUN_MULTIPLE_PRIORITIES 1 +#define configUSE_TASK_PREEMPTION_DISABLE 1 +#define configUSE_CORE_AFFINITY 1 +#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256 +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 2 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 /* Deprecated! */ +#define configQUEUE_REGISTRY_SIZE 10 +#define configUSE_QUEUE_SETS 1 +#define configUSE_TIME_SLICING 1 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 /* Required for FreeRTOS_TCP_WIN.c TODO: active closed bug, may have been fixed upstream */ +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 +#define configSTACK_DEPTH_TYPE uint32_t +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t + + +/* Memory allocation related definitions. */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configTOTAL_HEAP_SIZE 256*1024 +#define configAPPLICATION_ALLOCATED_HEAP 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configUSE_CORE_INIT_HOOK 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 0 +#define configUSE_STATS_FORMATTING_FUNCTIONS 2 /* Setting to 2 does not include in tasks.c */ + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 1 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE << 2 ) + +/* Define to trap errors during development. */ +#define configASSERT(x) xassert(x) + +/* Define to enable debug_printf() */ +#define configENABLE_DEBUG_PRINTF 0 + +/* Define to map sprintf and snprintf to the + * lite versions in lib_rtos_support */ + #include +#define configUSE_DEBUG_SPRINTF 1 + +/* Define to enable debug prints from tasks.c */ +#if ON_TILE(0) +#define configTASKS_DEBUG 0 +#endif +#if ON_TILE(1) +#define configTASKS_DEBUG 0 +#endif + +/* FreeRTOS MPU specific definitions. */ +#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xResumeFromISR 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xQueueGetMutexHolder 1 + +/* A header file that defines trace macro can be included here. */ +// #include "xcore_trace.h" + +#endif /* FREERTOS_CONFIG_H */ diff --git a/examples/freertos/xlink/src/app_conf.h b/examples/freertos/xlink/src/app_conf.h new file mode 100644 index 000000000..8cbfbd884 --- /dev/null +++ b/examples/freertos/xlink/src/app_conf.h @@ -0,0 +1,46 @@ +// Copyright 2021-2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef APP_CONF_H_ +#define APP_CONF_H_ + +/* XLINK Configuration */ +/* 0 = 2 wire; 1 = 5 wire */ +#define appconfXLINK_WIRE_TYPE 0 +#define appconfLINK_NUM 2 +#define appconfINTER_DELAY 2 +#define appconfINTRA_DELAY 3 + + +#define appconfRX_DIRECTION 0 +#define appconfRX_NODE_ID 0x20 +#define appconfRX_DEBUG_I2C_SLAVE_ADDR 0xc +#define appconfRX_TIME_OUT_TICKS 500000000 + +#define appconfTX_DIRECTION 5 +#define appconfRE_ENABLE_TX_PERIOD 6 +#define appconfSEND_CTRL_TOKEN 2500000 + +/* Intertile Communication Configuration */ +#define appconfI2C_MASTER_RPC_PORT 10 +#define appconfI2C_MASTER_RPC_PRIORITY (configMAX_PRIORITIES/2) + +#define appconfGPIO_T0_RPC_PORT 11 +#define appconfGPIO_T1_RPC_PORT 12 +#define appconfGPIO_RPC_PRIORITY (configMAX_PRIORITIES/2) + +/* I/O and interrupt cores for Tile 0 */ +#define appconfI2C_IO_CORE 3 /* Must be kept off core 0 with the RTOS tick ISR */ +#define appconfI2C_INTERRUPT_CORE 0 /* Must be kept off I/O cores. */ + +/* I/O and interrupt cores for Tile 1 */ +#define appconfXLINK_RX_IO_CORE 1 /* Must be kept off core 0 with the RTOS tick ISR */ +#define appconfXLINK_TX_IO_CORE 1 /* Must be kept off core 0 with the RTOS tick ISR */ + +/* Task Priorities */ +#define appconfSTARTUP_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define appconfGPIO_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) +#define appconfXLINK_RX_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define appconfXLINK_TX_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) + +#endif /* APP_CONF_H_ */ diff --git a/examples/freertos/xlink/src/link/link_helpers.c b/examples/freertos/xlink/src/link/link_helpers.c new file mode 100644 index 000000000..e5b5fc119 --- /dev/null +++ b/examples/freertos/xlink/src/link/link_helpers.c @@ -0,0 +1,70 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* System headers */ +#include +#include +#include + +/* Library headers */ + +/* App headers */ +#include "app_conf.h" +#include "link_helpers.h" +#include "platform/platform_init.h" +#include "platform/driver_instances.h" + +#ifdef appconfXLINK_WIRE_TYPE +#define W appconfXLINK_WIRE_TYPE +#else +/* default to 2 wire */ +#define W 0 +#endif + +/* Disable link by resetting ENABLE bit in link's control register */ +void link_disable(unsigned tileid, unsigned link_num) { + unsigned x = 0; + (void) read_sswitch_reg(tileid, XS1_SSWITCH_XLINK_0_NUM + link_num, &x); + x &= ~XS1_XLINK_ENABLE_MASK; + (void) write_sswitch_reg(tileid, XS1_SSWITCH_XLINK_0_NUM + link_num, x); +} + +/* Configure link by performing the following in the link's control register + * - Set intertoken and intratoken delays + * - Set ENABLE bit + * - Set WIDE bit if 5-bit link required + */ +void link_enable(unsigned tileid, unsigned link_num) { + unsigned x = 0; + (void) read_sswitch_reg(tileid, XS1_SSWITCH_XLINK_0_NUM + link_num, &x); + x |= XS1_XLINK_INTER_TOKEN_DELAY_SET(x, appconfINTER_DELAY); + x |= XS1_XLINK_INTRA_TOKEN_DELAY_SET(x, appconfINTRA_DELAY); + x |= XS1_XLINK_ENABLE_MASK; + x |= W * XS1_XLINK_WIDE_MASK; + (void) write_sswitch_reg(tileid, XS1_SSWITCH_XLINK_0_NUM + link_num, x); +} + +/* Reset link by setting RESET bit in link's control register */ +void link_reset(unsigned tileid, unsigned link_num) { + unsigned x = 0; + unsigned l = XS1_SSWITCH_XLINK_0_NUM + link_num; + (void) read_sswitch_reg(tileid, l, &x); + x |= XS1_XLINK_RX_RESET_MASK; + (void) write_sswitch_reg(tileid, l, x); +} + +/* Send a HELLO by setting HELLO bit in link's control register */ +void link_hello(unsigned tileid, unsigned link_num) { + unsigned x = 0; + unsigned l = XS1_SSWITCH_XLINK_0_NUM + link_num; + (void) read_sswitch_reg(tileid, l, &x); + x |= XS1_XLINK_HELLO_MASK; + (void) write_sswitch_reg(tileid, l, x); +} + +unsigned link_got_credit(unsigned tileid, unsigned link_num) { + unsigned x = 0; + unsigned l = XS1_SSWITCH_XLINK_0_NUM + link_num; + (void) read_sswitch_reg(tileid, l, &x); + return XS1_TX_CREDIT(x); +} \ No newline at end of file diff --git a/examples/freertos/xlink/src/link/link_helpers.h b/examples/freertos/xlink/src/link/link_helpers.h new file mode 100644 index 000000000..25370b44e --- /dev/null +++ b/examples/freertos/xlink/src/link/link_helpers.h @@ -0,0 +1,13 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef LINK_HELPERS_H_ +#define LINK_HELPERS_H_ + +void link_disable(unsigned tileid, unsigned link_num); +void link_enable(unsigned tileid, unsigned link_num); +void link_reset(unsigned tileid, unsigned link_num); +void link_hello(unsigned tileid, unsigned link_num); +unsigned link_got_credit(unsigned tileid, unsigned link_num); + +#endif /* LINK_HELPERS_H_ */ \ No newline at end of file diff --git a/examples/freertos/xlink/src/main.c b/examples/freertos/xlink/src/main.c new file mode 100644 index 000000000..8a17a8d16 --- /dev/null +++ b/examples/freertos/xlink/src/main.c @@ -0,0 +1,97 @@ +// Copyright 2019-2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* System headers */ +#include +#include + +/* FreeRTOS headers */ +#include "FreeRTOS.h" +#include "queue.h" + +/* Library headers */ + +/* App headers */ +#include "app_conf.h" +#include "link_helpers.h" +#include "xlink_rx.h" +#include "xlink_tx.h" +#include "platform/platform_init.h" +#include "platform/driver_instances.h" + +void vApplicationMallocFailedHook( void ) +{ + rtos_printf("Malloc Failed on tile %d!\n", THIS_XCORE_TILE); + for(;;); +} + +void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName) { + rtos_printf("\nStack Overflow!!! %d %s!\n", THIS_XCORE_TILE, pcTaskName); + configASSERT(0); +} + +void startup_task(void *arg) +{ + rtos_printf("Startup task running from tile %d on core %d\n", THIS_XCORE_TILE, portGET_CORE_ID()); + + platform_start(); + +#if ON_TILE(1) +#if DEMO_TILE == 0 + create_xlink_rx_tasks(appconfXLINK_RX_TASK_PRIORITY); +#else + create_xlink_tx_tasks(appconfXLINK_TX_TASK_PRIORITY); +#endif +#endif + +#if ON_TILE(0) + /* 1s Heartbeat */ + const rtos_gpio_port_id_t led_port = rtos_gpio_port(PORT_LEDS); + rtos_gpio_port_enable(gpio_ctx_t0, led_port); + int led_status=0; + + for (;;) { + rtos_gpio_port_out(gpio_ctx_t0, led_port, led_status); + led_status ^= 1; + vTaskDelay(pdMS_TO_TICKS(1000)); + } +#else + vTaskSuspend(NULL); +#endif +} + +static void tile_common_init(chanend_t c) +{ + platform_init(c); + chanend_free(c); + + xTaskCreate((TaskFunction_t) startup_task, + "startup_task", + RTOS_THREAD_STACK_SIZE(startup_task), + NULL, + appconfSTARTUP_TASK_PRIORITY, + NULL); + + rtos_printf("start scheduler on tile %d\n", THIS_XCORE_TILE); + vTaskStartScheduler(); +} + +#if ON_TILE(0) +void main_tile0(chanend_t c0, chanend_t c1, chanend_t c2, chanend_t c3) { + (void)c0; + (void)c2; + (void)c3; + + tile_common_init(c1); +} +#endif + +#if ON_TILE(1) +void main_tile1(chanend_t c0, chanend_t c1, chanend_t c2, chanend_t c3) { + (void)c1; + (void)c2; + (void)c3; + + tile_common_init(c0); +} +#endif diff --git a/examples/freertos/xlink/src/xlink_rx/xlink_rx.c b/examples/freertos/xlink/src/xlink_rx/xlink_rx.c new file mode 100644 index 000000000..777e61630 --- /dev/null +++ b/examples/freertos/xlink/src/xlink_rx/xlink_rx.c @@ -0,0 +1,190 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* System headers */ +#include +#include +#include +#include +#include +#include +#include + +/* Library headers */ + +/* App headers */ +#include "app_conf.h" +#include "link_helpers.h" +#include "xlink_rx.h" +#include "platform/platform_init.h" +#include "platform/driver_instances.h" + +static int g_data_tokens = 0; +static int g_ctrl_tokens = 0; +static int g_timeout_cnts = 0; + +/* XLINK RX debug info */ +#define RX_STATE_ID 0x01 +#define RX_REPORT_BYTES_PER_SEC_ID 0x82 +#define RX_REPORT_CTRL_TOKENS_PER_SEC_ID 0x83 +#define RX_REPORT_TIMEOUTS_PER_SEC_ID 0x84 + +static void i2c_send_word(uint8_t id, uint32_t word) { + uint8_t debug_buf[5] = {0}; + size_t n = 0; + + debug_buf[0] = id; + memcpy(&debug_buf[1], &word, sizeof(uint32_t)); + rtos_i2c_master_write(i2c_master_ctx, appconfRX_DEBUG_I2C_SLAVE_ADDR, debug_buf, sizeof(debug_buf), &n, 1); +} + +void xlink_report_task(void) { + int full_rep_cnt = 0; + uint8_t debug_buf[5] = {0}; + size_t n = 0; + + while(1) { + vTaskDelay(pdMS_TO_TICKS(1000)); + i2c_send_word(RX_REPORT_BYTES_PER_SEC_ID, g_data_tokens); + if (!(full_rep_cnt++ % 10)) { + i2c_send_word(RX_REPORT_CTRL_TOKENS_PER_SEC_ID, g_ctrl_tokens); + i2c_send_word(RX_REPORT_TIMEOUTS_PER_SEC_ID, g_timeout_cnts); + } + g_data_tokens = 0; + } +} + +void xlink_rx(void) { + unsigned comm_state = 0; + chanend_t c_tileid = 0; + unsigned tm_out_ctr = 0; + unsigned rx_loop = 0; + + uint32_t last_time = 0; + hwtimer_t tmr_rx = hwtimer_alloc(); + char rx = 'z'; + uint32_t id = 0; + int reg_val = 0; + int direction = 0x0; + + unsigned x = 0; + + rtos_osal_thread_core_exclusion_set(NULL, ~(1 << appconfXLINK_RX_IO_CORE)); + rtos_osal_thread_preemption_disable(NULL); + + while(1) { + i2c_send_word(RX_STATE_ID, comm_state); + + switch (comm_state) { + default: + break; + case 0: /* Setup link direction */ + reg_val = 0; + direction = appconfRX_DIRECTION; + reg_val = XS1_LINK_DIRECTION_SET(reg_val, direction); + (void) write_sswitch_reg(appconfRX_NODE_ID, XS1_SSWITCH_SLINK_0_NUM + appconfLINK_NUM, reg_val); + comm_state = 1; + break; + case 1: /* Channel alloc */ + c_tileid = chanend_alloc(); + comm_state = 2; + break; + case 2: /* Reconfigure links, setting up a single static link */ + for (int i=0; i<8; i++) { + link_disable(appconfRX_NODE_ID, i); + } + link_enable(appconfRX_NODE_ID, appconfLINK_NUM); + delay_milliseconds(100); + + x = 0; + x |= XS1_XSTATIC_ENABLE_SET(x, 1); + x |= XS1_XSTATIC_DEST_CHAN_END_SET(x, ((c_tileid >> 8) & 0x0000001F)); + x |= XS1_XSTATIC_DEST_PROC_SET(x, 1); + + (void) write_sswitch_reg(appconfRX_NODE_ID, XS1_SSWITCH_XSTATIC_0_NUM + appconfLINK_NUM, x); + + delay_milliseconds(100); + + comm_state = 3; + break; + case 3: /* Wait for transmit credits */ + do { + link_reset(appconfRX_NODE_ID, appconfLINK_NUM); + link_hello(appconfRX_NODE_ID, appconfLINK_NUM); + delay_milliseconds(100); + + } while (!link_got_credit(appconfRX_NODE_ID, appconfLINK_NUM)); + + /* Setup local control vars */ + rx_loop = 1; + tm_out_ctr++; + last_time = get_reference_time(); + comm_state = 4; + break; + case 4: /* Receive data loop */ + rx = 'z'; + + TRIGGERABLE_SETUP_EVENT_VECTOR(tmr_rx, timeout); + TRIGGERABLE_SETUP_EVENT_VECTOR(c_tileid, transaction); + + triggerable_disable_all(); + + uint32_t trigger_time = hwtimer_get_time(tmr_rx) + appconfRX_TIME_OUT_TICKS; + hwtimer_set_trigger_time(tmr_rx, trigger_time); + triggerable_enable_trigger(tmr_rx); + triggerable_enable_trigger(c_tileid); + + while(rx_loop) { + TRIGGERABLE_WAIT_EVENT(timeout, transaction); + { + transaction: + { + if (chanend_test_control_token_next_byte(c_tileid)) { + rx = chanend_in_control_token(c_tileid); + g_ctrl_tokens++; + } else { + rx = chanend_in_byte(c_tileid); + g_data_tokens++; + } + triggerable_disable_trigger(tmr_rx); + hwtimer_clear_trigger_time(tmr_rx); + trigger_time = hwtimer_get_time(tmr_rx) + appconfRX_TIME_OUT_TICKS; + hwtimer_set_trigger_time(tmr_rx, trigger_time); + triggerable_enable_trigger(tmr_rx); + continue; + } + timeout: + { + triggerable_disable_trigger(c_tileid); + triggerable_disable_trigger(tmr_rx); + rx_loop = 0; + comm_state = 3; + continue; + } + } + } + break; + case 6: /* End of Communication */ + chanend_free(c_tileid); + link_disable(appconfRX_NODE_ID, appconfLINK_NUM); + comm_state = 1; + break; + } + } +} + +void create_xlink_rx_tasks(unsigned priority) { + xTaskCreate((TaskFunction_t) xlink_report_task, + "xlink_report_task", + RTOS_THREAD_STACK_SIZE(xlink_report_task), + NULL, + priority, + NULL); + + xTaskCreate((TaskFunction_t) xlink_rx, + "xlink_rx", + RTOS_THREAD_STACK_SIZE(xlink_rx), + NULL, + priority, + NULL); +} \ No newline at end of file diff --git a/examples/freertos/xlink/src/xlink_rx/xlink_rx.h b/examples/freertos/xlink/src/xlink_rx/xlink_rx.h new file mode 100644 index 000000000..a4308d7be --- /dev/null +++ b/examples/freertos/xlink/src/xlink_rx/xlink_rx.h @@ -0,0 +1,9 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef XLINK_RX_H_ +#define XLINK_RX_H_ + +void create_xlink_rx_tasks(unsigned priority); + +#endif /* XLINK_RX_H_ */ \ No newline at end of file diff --git a/examples/freertos/xlink/src/xlink_tx/xlink_tx.c b/examples/freertos/xlink/src/xlink_tx/xlink_tx.c new file mode 100644 index 000000000..142eb03cd --- /dev/null +++ b/examples/freertos/xlink/src/xlink_tx/xlink_tx.c @@ -0,0 +1,144 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* System headers */ +#include +#include +#include +#include +#include +#include +#include + +/* Library headers */ +#include "trycatch.h" + +/* App headers */ +#include "app_conf.h" +#include "link_helpers.h" +#include "xlink_tx.h" +#include "platform/platform_init.h" +#include "platform/driver_instances.h" + +static unsigned g_comm_state = 0; + +void xlink_tx_reenable(void) { + while(1) { + vTaskDelay(pdMS_TO_TICKS(appconfRE_ENABLE_TX_PERIOD * 1000)); + g_comm_state = 1; + /* Reenable tx link */ + link_disable(get_local_tile_id(), appconfLINK_NUM); + link_enable(get_local_tile_id(), appconfLINK_NUM); + } +} + +void transmit_handler(unsigned comm_state) { + chanend_t c_other_tile = 0; + unsigned err_ctr = 0; + int reg_val = 0; + int direction = 0x0; + int ret = 0; + + unsigned x = 0; + + unsigned switch_id = get_local_tile_id(); + + while(1) { + if (g_comm_state) { + g_comm_state = 0; + comm_state = 4; + } + switch (comm_state) { + default: + comm_state = 4; + break; + case 0: /* Setup Link Direction */ + reg_val = 0; + direction = appconfTX_DIRECTION; + reg_val = XS1_LINK_DIRECTION_SET(reg_val, direction); + (void) write_sswitch_reg(switch_id, XS1_SSWITCH_SLINK_0_NUM + appconfLINK_NUM, reg_val); + comm_state = 1; + break; + case 1: /* Channel setup */ + c_other_tile = chanend_alloc(); + chanend_set_dest(c_other_tile, 0x00210902); // hardcode to expected rx + + (void) read_sswitch_reg(switch_id, XS1_SSWITCH_DIMENSION_DIRECTION1_NUM, &x); + x = XS1_DIMF_DIR_SET(x, appconfTX_DIRECTION); + (void) write_sswitch_reg(switch_id, XS1_SSWITCH_DIMENSION_DIRECTION1_NUM, x); + + comm_state = 2; + break; + case 2: /* reconfigure links, leaving only one open */ + for (int i=0; i<8; i++) { + link_disable(switch_id, i); + } + link_enable(switch_id, appconfLINK_NUM); + comm_state = 3; + break; + case 3: /* Setup a static routing configuration */ + x = 0; + x |= XS1_XSTATIC_ENABLE_SET(x, 1); + x = write_sswitch_reg(switch_id, XS1_SSWITCH_XSTATIC_0_NUM + appconfLINK_NUM, x); + + delay_milliseconds(150); + + comm_state = 4; + break; + case 4: /* Wait for transmit credits */ + do { + link_reset(switch_id, appconfLINK_NUM); + link_hello(switch_id, appconfLINK_NUM); + delay_milliseconds(100); + } while (!link_got_credit(switch_id, appconfLINK_NUM)); + + /* Setup local control vars */ + err_ctr = 0; + comm_state = 5; + break; + case 5: /* Send data tokens */ + chanend_out_byte(c_other_tile, 'a'); + + if (err_ctr++ == appconfSEND_CTRL_TOKEN) { + err_ctr = 0; + chanend_out_control_token(c_other_tile, XS1_CT_ACK); + } + break; + case 6: + chanend_free(c_other_tile); + link_disable(switch_id, appconfLINK_NUM); + comm_state = 2; + break; + } + } +} + +void xlink_tx(void) { + exception_t exception; + + rtos_osal_thread_core_exclusion_set(NULL, ~(1 << appconfXLINK_TX_IO_CORE)); + rtos_osal_thread_preemption_disable(NULL); + while(1) { + TRY { + transmit_handler(0); + } CATCH (exception) { + transmit_handler(4); + } + } +} + +void create_xlink_tx_tasks(unsigned priority) { + xTaskCreate((TaskFunction_t) xlink_tx_reenable, + "xlink_tx_reenable", + RTOS_THREAD_STACK_SIZE(xlink_tx_reenable), + NULL, + priority, + NULL); + + xTaskCreate((TaskFunction_t) xlink_tx, + "xlink_tx", + RTOS_THREAD_STACK_SIZE(xlink_tx), + NULL, + priority, + NULL); +} \ No newline at end of file diff --git a/examples/freertos/xlink/src/xlink_tx/xlink_tx.h b/examples/freertos/xlink/src/xlink_tx/xlink_tx.h new file mode 100644 index 000000000..3986a4a3b --- /dev/null +++ b/examples/freertos/xlink/src/xlink_tx/xlink_tx.h @@ -0,0 +1,9 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +#ifndef XLINK_TX_H_ +#define XLINK_TX_H_ + +void create_xlink_tx_tasks(unsigned priority); + +#endif /* XLINK_TX_H_ */ \ No newline at end of file diff --git a/examples/freertos/xlink/xlink.cmake b/examples/freertos/xlink/xlink.cmake new file mode 100644 index 000000000..545db83a9 --- /dev/null +++ b/examples/freertos/xlink/xlink.cmake @@ -0,0 +1,148 @@ +query_tools_version() + +if ((XTC_VERSION_MAJOR LESS 15) OR (XTC_VERSION_MINOR LESS 2)) + message(WARNING "XTC Tools version 15.2.0 or newer required for FreeRTOS xlink example") + return() +endif() + +#********************** +# 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/link + ${CMAKE_CURRENT_LIST_DIR}/src/xlink_rx + ${CMAKE_CURRENT_LIST_DIR}/src/xlink_tx +) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/bsp_config) + +#********************** +# Flags +#********************** +set(APP_COMPILER_FLAGS + -Os + -g + -report + -fxscope + -lquadspi + -mcmodel=large + -Wno-xcore-fptrgroup +) +set(APP_COMPILE_DEFINITIONS + DEBUG_PRINT_ENABLE=1 + PLATFORM_USES_TILE_0=1 + PLATFORM_USES_TILE_1=1 + XE_BASE_TILE=0 + + XUD_CORE_CLOCK=600 +) + +set(RX_APP_COMPILER_FLAGS + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn +) + +set(TX_APP_COMPILER_FLAGS + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER_tx.xn +) + +set(APP_LINK_OPTIONS + -lquadspi + -report +) + +set(RX_APP_LINK_OPTIONS + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn +) + +set(TX_APP_LINK_OPTIONS + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER_tx.xn +) + +set(APP_LINK_LIBRARIES + example::freertos::xlink::bsp_config::xcore_ai_explorer_2V0 +) + +#********************** +# Tile Targets +#********************** +set(TARGET_NAME tile0_example_freertos_xlink_0) +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 ${APP_COMPILE_DEFINITIONS} DEMO_TILE=0 THIS_XCORE_TILE=0) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS} ${RX_APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS} ${RX_APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +set(TARGET_NAME tile1_example_freertos_xlink_0) +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 ${APP_COMPILE_DEFINITIONS} DEMO_TILE=0 THIS_XCORE_TILE=1) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS} ${RX_APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS} ${RX_APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +#********************** +# Merge binaries +#********************** +merge_binaries(example_freertos_xlink_0 tile0_example_freertos_xlink_0 tile1_example_freertos_xlink_0 1) + +#********************** +# Create run and debug targets +#********************** +create_run_target(example_freertos_xlink_0) +create_debug_target(example_freertos_xlink_0) + + +#********************** +# Tile Targets +#********************** +set(TARGET_NAME tile0_example_freertos_xlink_1) +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 ${APP_COMPILE_DEFINITIONS} DEMO_TILE=1 THIS_XCORE_TILE=0) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS} ${TX_APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS} ${TX_APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +set(TARGET_NAME tile1_example_freertos_xlink_1) +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 ${APP_COMPILE_DEFINITIONS} DEMO_TILE=1 THIS_XCORE_TILE=1) +target_compile_options(${TARGET_NAME} PRIVATE ${APP_COMPILER_FLAGS} ${TX_APP_COMPILER_FLAGS}) +target_link_libraries(${TARGET_NAME} PUBLIC ${APP_LINK_LIBRARIES}) +target_link_options(${TARGET_NAME} PRIVATE ${APP_LINK_OPTIONS} ${TX_APP_LINK_OPTIONS}) +unset(TARGET_NAME) + +#********************** +# Merge binaries +#********************** +merge_binaries(example_freertos_xlink_1 tile0_example_freertos_xlink_1 tile1_example_freertos_xlink_1 1) + +#********************** +# Create run and debug targets +#********************** +create_run_target(example_freertos_xlink_1) +create_debug_target(example_freertos_xlink_1) +create_install_target(example_freertos_xlink_0) +create_install_target(example_freertos_xlink_1) + +#********************** +# Create custom target to build both example applications +#********************** +add_custom_target(example_freertos_xlink_both + COMMAND + DEPENDS + example_freertos_xlink_0 + example_freertos_xlink_1 + COMMENT + "Create both xlink example applications" + VERBATIM +) \ No newline at end of file diff --git a/examples/freertos/xscope_fileio/README.rst b/examples/freertos/xscope_fileio/README.rst new file mode 100644 index 000000000..92937f22f --- /dev/null +++ b/examples/freertos/xscope_fileio/README.rst @@ -0,0 +1,142 @@ +############### +XSCOPE File I/O +############### + +This FreeRTOS example application reads a WAV file from the host over an XSCOPE server, propagates the data through multiple threads across both tiles, and then writes the output to a WAV file on the host PC, also over an XSCOPE server. + +.. image:: images/xscope_fileio_functional_diagram.png + :align: left + +The 3-stage pipeline in the example covers both XCORE tiles. Stage #1 and Stage #2 run on tile[1], while Stage #3 runs on tile[0]. + +Stages #1 and #2 are implemented in the functions `stage_1` and `stage_2` which can be found in the file ``src\data_pipeline\src\data_pipeline_tile1.c``. In this example, both stages apply a fixed gain to the PCM audio samples. In `stage_1`, preemption is disabled with the `rtos_interrupt_mask_all()` function to insure the FreeRTOS kernel does not interrupt the task and perform a context switch during a performance critical code section. `stage_2` is a typical FreeRTOS task which can be preempted. However, this example is rather simple so, instead of leaving a context switch up to chance, the `stage_2` function periodically yields to the FreeRTOS kernel - emulating a context switch. + +Both the `stage_1` and `stage_2` functions have been instrumented with a stopwatch-like timer to measure the time spent applying the fixed gain. + +Stage #3 is implemented in the function `stage_3` which can be found in the file ``src\data_pipeline\src\data_pipeline_tile0.c``. In this example, Stage 3 does nothing. It is provided to demonstrate a multi-tile pipeline. + +The example application input file name is hard-coded to `in.wav` and the output file file name is hard-coded to `out.wav`. Running the application can be wrapped in a simple script if alternative file names are desired. Simply copy your file to `in.wav`, run the applications, then copy `out.wav` to you preferred output file name. + +The example input file provided is 16 KHz, however, 48 KHz will also work. The input file sample rate must be 32 bits per sample. + +This example is already configured to link with the `XMOS vectorized math library `_. Users wishing to take advantage of the vector processing unit (VPU) on the XMOS XS3 architecture can use this example application as a starting point. + +****************** +Supported Hardware +****************** + +This example is supported on the XCORE-AI-EXPLORER board. + +********************* +Building the Firmware +********************* + +Run the following commands in the root folder to build the embedded application using the XTC Toolchain: + +Linux or Mac +------------ + +.. code-block:: console + + cmake -B build -DCMAKE_TOOLCHAIN_FILE=xmos_cmake_toolchain/xs3a.cmake + cd build + make example_freertos_xscope_fileio + +Windows +------- + +Before building the embedded application, you may need to add the path to nmake to your PATH variable. + +.. code-block:: console + + set PATH=%PATH%; + +To build the embedded application: + +.. code-block:: console + + cmake -G "NMake Makefiles" -B build -DCMAKE_TOOLCHAIN_FILE=xmos_cmake_toolchain/xs3a.cmake + cd build + nmake example_freertos_xscope_fileio + +********************* +Building the Host App +********************* + +Run the following commands in the root folder to build the host application using your native x86 Toolchain: + +.. note:: + + Permissions may be required to install the host applications. + +Linux or Mac +------------ + +.. code-block:: console + + cmake -B build_host + cd build_host + make xscope_host_endpoint + make install + +The host application, `xscope_host_endpoint`, will be installed at `/opt/xmos/SDK//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 `__. + +Windows +------- + +Before building the host application, you will need to add the path to the XTC Tools to your environment. + +.. code-block:: console + + set "XMOS_TOOL_PATH=" + +Then build the host application: + +.. code-block:: console + + cmake -G "NMake Makefiles" -B build_host + cd build_host + nmake xscope_host_endpoint + nmake install + +The host application, `xscope_host_endpoint.exe`, will be install at `\.xmos\SDK\\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 `__. + +******************** +Running the Firmware +******************** + +From the build folder run: + +Linux or Mac +------------ + +.. code-block:: console + + make run_example_freertos_xscope_fileio + +In a second console, run the host xscope server: + +.. code-block:: console + + ./xscope_host_endpoint 12345 + +Windows +------- + +.. code-block:: console + + nmake run_example_freertos_xscope_fileio + +.. code-block:: console + + set PATH=%PATH%; + +In a second console, run the host xscope server: + +.. code-block:: console + + xscope_host_endpoint.exe 12345 diff --git a/examples/freertos/xscope_fileio/XCORE-AI-EXPLORER.xn b/examples/freertos/xscope_fileio/XCORE-AI-EXPLORER.xn new file mode 100644 index 000000000..4dde19f84 --- /dev/null +++ b/examples/freertos/xscope_fileio/XCORE-AI-EXPLORER.xn @@ -0,0 +1,109 @@ + + + Board + xcore.ai Explorer Kit + + + tileref tile[2] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/freertos/xscope_fileio/diagrams/functional_diagram.drawio b/examples/freertos/xscope_fileio/diagrams/functional_diagram.drawio new file mode 100644 index 000000000..b711515b3 --- /dev/null +++ b/examples/freertos/xscope_fileio/diagrams/functional_diagram.drawio @@ -0,0 +1 @@ +7V1fd5s2HP00frQPkkDAY+M2a7fTdVuys+Zph9qKzYqNBzhx9uknAQIkwIAjwE7tnlMbIQTWvbr8/uFM0Hxz+ClwduvP/pJ4E6gtDxP0fgIhgLZF31jLS9JiQjNpWAXuMu2UN9y5/5G0UUtb9+6ShELHyPe9yN2JjQt/uyWLSGhzgsB/Frs9+p541p2zIqWGu4XjlVv/cpfROmm1DC1v/0jc1ZqfGWjpno3DO6cN4dpZ+s+FJvRhguaB70fJp81hTjw2eXxekuNua/ZmFxaQbdTmgPWj8ffTevXySwgefsXP/p9P//w8TUd5crx9+oUnEHt0vJtHnw5Lrzp6SacC/7v3+Y5pGAP1jnYA1u6Q76SfVuz93qVHQTYXyWj0spIBk93pjGRjw8Dfb5eEXalGdz+v3Yjc7ZwF2/tMiUXb1tHGo1uAfnwiQeRSiN557mpL2yKfdXh0PW/ue34Qj4g+YPYvOxc7hhxqpw5kgFAmE39DouCFdkkPgBzUlMRWuvmcMwLzLusiGzTe6qQ0XGVj50jRDylYHYCD/QIH3gZwOQD1yBl4WORQT8gd7p7daLF+G8BZeiNuAA6Lm94TbrcBIX/cf7nrDhxoBk6CaD6/pa9aQFVIpQRchlJxxVUhZ8O+gDOuwLWSyhbI6dagyOEK5KRJJdvlO2bm0a2F54ShuxDnkRzc6CsTuZlt2+n2Q7yNDCvdfn9IVTDeeOEbW/oVkkM1DfAGfqzNG/KD462XwlC/kcClE0GCYg+5MYwC/3tmW6IMTLIsGaYSlHQe/H2wIM2aFTnBikRNS6RMjeKarQCetwXEcyL3SbzcKjKkZ/jNd+N1lzIPWyLxdFnCk6+ZHlW0cKWBTCQOhAxpoGQeSgPF3My+9ul0NXsSmqLIfAt466ctJdE0iu01ed987VB3yGurTFQ1InHZOKm8LMg2pmpJdzbucskOvwkIvXznWzwU4/OOzW4838bNxHjPToduPOcb8W6cxfdVLIKdjIbUs0tPMcn8qeJ6qFePWr2bajMMdFOUPCV8toyZZdr5yxLOMUW2OKD/+BiSXvhoKZRPQTpNo51ySqqZHHZENHvVQqOlFupjamHJYcHyzbWtGALNEEcyzGHV0L6q4TmpodWkhga0oBIOT019BqAoerrEvf5EjwcOew9p5fz67LhbuufeCb+35Rj9Iu4uJJ39ANtmnoAai1+HksGPWzrZVl/2Pug5HAneDHYAnh94fYUkbxPwPm13ezbKbeBv6NtHP4wuEDhoS84OGB23vgKSKW5f9lEC3L3/dmDDGI0NW1U8st663/pbNoNLJ1xnIaiinZ8FO0STvcliz8Mr3CV4KHoEle7BRJ1NzzWn0agHWjW8A1n1WGSPLQcm2hr1WVqUDySHSmpsesoC56XQLTVLay8YSb4DRNrR6yr114T+9ENyBWotvd4Cu37QWpxGdBaymHCtvp3sLIAaJzgdngVAddH8ULJOEJiZhl0bOpHG69GH6BZ4bq2tuZw+FPedqbaiq7YOoa1YO66tunW0f0/a2lcs+4fS1gb/W2eZJap3yNJ1YBg6FnGG+owqILUgDQyQgY2uK2NqGDNDHHNqzPTBRLQq/HylkFIK0bsl5UhOIUO0woAtMgheGoWqYsj19+GjGQz+ueDX1N5Fy3mIpEVAV9Pm80l9siNNLx+7v1elg1XewNs6R+NmPFTdv03pvqrr1ivv36rpzNd3TykR7TMJQ1bOWgpy/r4ne3JJkskusGqxvUpKj0jMsbwIwAYSFVCNswPMGRb1eooG83BgVaS9q7LW+DVak+6lijzNCmsKNTm8RkeBMFdU4ChU17bp5KTefSx1RVI6GYET1RVLAVCkMdui5Kkr9pUAkMPlxgDOD18LV50eRacbMl8gdpugrQNgYt3U9EqCXIwQV2VfThbibsH7FmqqaTaLg3RRzuZ4ERxTEeViw1PNTTWCqIxGfVWnf71b+DuWxuNZ2C8XoE+P8ausTxKbVdqRyTo+ZkcyB11gjBozcmrNeN1OZp8OVmEIq1IwHdWriwpVlyMed+YV2nygBuRhlEsXBcYUa1dPtuwkQTQ1NKxyVeVarso1oHLVFP/nuT4bSyFARcoF4MzWJ2NJV18ZjksrbQFAemzCGL0kCfaVOrg0bLKa7bMpO4IKQvL1MZuyLfDaIJOYPOfRpt4tBa4uzbH3GgIMY1JI9ALgVG8IyGF8PPCzV1zDBuellPZpXTA3jgXLlbXZSR/V1FXHS7lMGrSs6lDGSwWB9tP0UuRl47NXIwum3jZ6NOqjquPz8tURdAsMEEFH8DyshLYldmIWquHxRpWsb0l6WPP01pX1NcFZNAbpu4XyG6pGK4Jg7FWiv5AAONEYEeh/fqbIqPWll0d++WcQ+CPEbX82YZDifaT08ZVOi6Uz6U+9u6hcLG39SfBG/EmkV5NSuX1USghaQ7C/W97kR2d/a+dgXPZTRYcz2zQsW4eI/ic9BI8xnumUX9jGiP1QllTQff5LA+tDLI2+8kHXsvEChbSjdePYvugnD1C/P8R0rd961VMvFivfQjYyMbCwZQKxuNY0492QCqUJMLC6Um/UYi7UV97qSrzXEw8jiXgCS6yL5l2/v7V05d2rbrbUPnurxOOWaAXxwp2zPZ14En0XGWR5R+7llAt/5n7ACn6afvYra04u9cpaofLAPkZaBC+ZtL39ytSFVZeUKn8wB6WH8hK6mf+tgwTK/C9GoA//Aw== \ No newline at end of file diff --git a/examples/freertos/xscope_fileio/images/xscope_fileio_functional_diagram.png b/examples/freertos/xscope_fileio/images/xscope_fileio_functional_diagram.png new file mode 100644 index 000000000..6635c3d19 Binary files /dev/null and b/examples/freertos/xscope_fileio/images/xscope_fileio_functional_diagram.png differ diff --git a/examples/freertos/xscope_fileio/in.wav b/examples/freertos/xscope_fileio/in.wav new file mode 100644 index 000000000..490d72c9c Binary files /dev/null and b/examples/freertos/xscope_fileio/in.wav differ diff --git a/examples/freertos/xscope_fileio/src/FreeRTOSConfig.h b/examples/freertos/xscope_fileio/src/FreeRTOSConfig.h new file mode 100644 index 000000000..e363c443b --- /dev/null +++ b/examples/freertos/xscope_fileio/src/FreeRTOSConfig.h @@ -0,0 +1,123 @@ +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/* Here is a good place to include header files that are required across +your application. */ +#include "platform.h" + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 0 +#define configCPU_CLOCK_HZ 100000000 + +#define configNUM_CORES 7 +#define configTICK_RATE_HZ 1000 +#define configMAX_PRIORITIES 32 +#define configRUN_MULTIPLE_PRIORITIES 1 +#define configUSE_TASK_PREEMPTION_DISABLE 1 +#define configUSE_CORE_AFFINITY 1 +#define configMINIMAL_STACK_SIZE ( configSTACK_DEPTH_TYPE ) 256 +#define configMAX_TASK_NAME_LEN 32 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 10 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configSTACK_DEPTH_TYPE uint32_t +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t + +/* Memory allocation related definitions. */ +#define configSUPPORT_STATIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#if ON_TILE(0) +#define configTOTAL_HEAP_SIZE 128*1024 +#endif +#if ON_TILE(1) +#define configTOTAL_HEAP_SIZE 128*1024 +#endif +#define configAPPLICATION_ALLOCATED_HEAP 0 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_MINIMAL_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 +#define configUSE_CORE_INIT_HOOK 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#if ENABLE_RTOS_XSCOPE_TRACE +#define configUSE_TRACE_FACILITY 1 +#else +#define configUSE_TRACE_FACILITY 0 +#endif +#define configUSE_STATS_FORMATTING_FUNCTIONS 2 /* Setting to 2 does not include in tasks.c */ + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 1 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE << 2 ) + +/* Define to trap errors during development. */ +#define configASSERT(x) xassert(x) + +/* Define to enable debug_printf() */ +#define configENABLE_DEBUG_PRINTF 1 + +/* Define to map sprintf and snprintf to the + * lite versions in lib_rtos_support */ + #include +#define configUSE_DEBUG_SPRINTF 1 + +/* Define to enable debug prints from tasks.c */ +#if ON_TILE(0) +#define configTASKS_DEBUG 0 +#endif +#if ON_TILE(1) +#define configTASKS_DEBUG 0 +#endif + +/* FreeRTOS MPU specific definitions. */ +#define configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS 0 + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xResumeFromISR 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xQueueGetMutexHolder 1 + +/* A header file that defines trace macro can be included here. */ +#if ENABLE_RTOS_XSCOPE_TRACE +#include "xcore_trace.h" +#endif + +#endif /* FREERTOS_CONFIG_H */ diff --git a/examples/freertos/xscope_fileio/src/app_conf.h b/examples/freertos/xscope_fileio/src/app_conf.h new file mode 100644 index 000000000..783abbd15 --- /dev/null +++ b/examples/freertos/xscope_fileio/src/app_conf.h @@ -0,0 +1,28 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#ifndef APP_CONF_H_ +#define APP_CONF_H_ + +/* Intertile port settings */ +#define appconfEXAMPLE_DATA_PORT 16 + +/* Application tile specifiers */ +#include "platform/driver_instances.h" + +/* App configuration */ +#define appconfINPUT_FILENAME "in.wav\0" +#define appconfOUTPUT_FILENAME "out.wav\0" +#define appconfMAX_CHANNELS 1 +#define appconfFRAME_ADVANCE 240 +#define appconfFRAME_ELEMENT_SIZE sizeof(int32_t) +#define appconfDATA_FRAME_SIZE_BYTES (appconfFRAME_ADVANCE * appconfFRAME_ELEMENT_SIZE) + +#define appconfAPP_NOTIFY_FILEIO_DONE 0 + +/* Task Priorities */ +#define appconfSTARTUP_TASK_PRIORITY (configMAX_PRIORITIES - 2) +#define appconfXSCOPE_IO_TASK_PRIORITY (configMAX_PRIORITIES - 1) +#define appconfDATA_PIPELINE_TASK_PRIORITY (configMAX_PRIORITIES - 1) + +#endif /* APP_CONF_H_ */ diff --git a/examples/freertos/xscope_fileio/src/config.xscope b/examples/freertos/xscope_fileio/src/config.xscope new file mode 100644 index 000000000..71b449388 --- /dev/null +++ b/examples/freertos/xscope_fileio/src/config.xscope @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/freertos/xscope_fileio/src/data_pipeline/api/data_pipeline.h b/examples/freertos/xscope_fileio/src/data_pipeline/api/data_pipeline.h new file mode 100644 index 000000000..c80bc982f --- /dev/null +++ b/examples/freertos/xscope_fileio/src/data_pipeline/api/data_pipeline.h @@ -0,0 +1,31 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#ifndef DATA_PIPELINE_H_ +#define DATA_PIPELINE_H_ + +#include +#include "app_conf.h" + +#define DATA_PIPELINE_DONT_FREE_FRAME 0 +#define DATA_PIPELINE_FREE_FRAME 1 + +typedef struct { + int32_t data[appconfFRAME_ADVANCE]; +} frame_data_t; + +void data_pipeline_init( + void *input_app_data, + void *output_app_data); + +void data_pipeline_input( + void *input_app_data, + int8_t **input_data_frame, + size_t frame_count); + +int data_pipeline_output( + void *output_app_data, + int8_t **output_data_frame, + size_t frame_count); + +#endif /* DATA_PIPELINE_H_ */ diff --git a/examples/freertos/xscope_fileio/src/data_pipeline/src/data_pipeline_tile0.c b/examples/freertos/xscope_fileio/src/data_pipeline/src/data_pipeline_tile0.c new file mode 100644 index 000000000..c50627e7c --- /dev/null +++ b/examples/freertos/xscope_fileio/src/data_pipeline/src/data_pipeline_tile0.c @@ -0,0 +1,83 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +/* STD headers */ +#include +#include +#include + +/* FreeRTOS headers */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* Library headers */ +#include "generic_pipeline.h" + +/* App headers */ +#include "app_conf.h" +#include "data_pipeline.h" + +#if ON_TILE(0) + +static void *data_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)); + + size_t bytes_received = 0; + bytes_received = rtos_intertile_rx_len( + intertile_ctx, + appconfEXAMPLE_DATA_PORT, + portMAX_DELAY); + + xassert(bytes_received == sizeof(frame_data_t)); + + rtos_intertile_rx_data( + intertile_ctx, + frame_data, + bytes_received); + + return frame_data; +} + +static int data_pipeline_output_i(frame_data_t *frame_data, + void *output_app_data) +{ + return data_pipeline_output(output_app_data, + (int8_t **)frame_data->data, + appconfDATA_FRAME_SIZE_BYTES); +} + +static void stage_3(frame_data_t *frame_data) +{ + /* Do nothing */ +} + +void data_pipeline_init( + void *input_app_data, + void *output_app_data) +{ + const int stage_count = 1; + + const pipeline_stage_t stages[] = { + (pipeline_stage_t) stage_3, + }; + + const configSTACK_DEPTH_TYPE stage_stack_sizes[] = { + configMINIMAL_STACK_SIZE + RTOS_THREAD_STACK_SIZE(stage_3) + RTOS_THREAD_STACK_SIZE(data_pipeline_input_i) + RTOS_THREAD_STACK_SIZE(data_pipeline_output_i), + }; + + generic_pipeline_init((pipeline_input_t)data_pipeline_input_i, + (pipeline_output_t)data_pipeline_output_i, + input_app_data, + output_app_data, + stages, + (const size_t*) stage_stack_sizes, + appconfDATA_PIPELINE_TASK_PRIORITY, + stage_count); +} + +#endif /* ON_TILE(0)*/ diff --git a/examples/freertos/xscope_fileio/src/data_pipeline/src/data_pipeline_tile1.c b/examples/freertos/xscope_fileio/src/data_pipeline/src/data_pipeline_tile1.c new file mode 100644 index 000000000..cc67ebfa0 --- /dev/null +++ b/examples/freertos/xscope_fileio/src/data_pipeline/src/data_pipeline_tile1.c @@ -0,0 +1,114 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +/* STD headers */ +#include +#include +#include + +/* FreeRTOS headers */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* Library headers */ +#include "generic_pipeline.h" + +/* App headers */ +#include "app_conf.h" +#include "data_pipeline.h" + +#if ON_TILE(1) + +static void *data_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)); + + data_pipeline_input(input_app_data, + (int8_t **)frame_data->data, + appconfDATA_FRAME_SIZE_BYTES); + + return frame_data; +} + +static int data_pipeline_output_i(frame_data_t *frame_data, + void *output_app_data) +{ + rtos_intertile_tx(intertile_ctx, + appconfEXAMPLE_DATA_PORT, + frame_data, + sizeof(frame_data_t)); + return DATA_PIPELINE_FREE_FRAME; +} + +static void stage_preemption_disabled(frame_data_t *frame_data) +{ + uint32_t time_start, time_end; + + // Disable preemption around the performance critical code section that follows + uint32_t mask = rtos_interrupt_mask_all(); + { + time_start = get_reference_time(); + /* Apply a fixed gain to all samples */ + for (int i=0; idata[i] *= 2; + } + time_end = get_reference_time(); + } + rtos_interrupt_mask_set(mask); // Enable preemption + + rtos_printf("stage_preemption_disabled: %d (microseconds) \n", (time_end - time_start) / 100); +} + +static void stage_preemption_enabled(frame_data_t *frame_data) +{ + uint32_t time_start, time_end; + + // Preemption is not disabled around the code section that follows + // Instead, the code periodically yields to the RTOS kernel to + // emulate a task context switch. + + time_start = get_reference_time(); + /* Apply a fixed gain to all samples */ + for (int i=0; idata[i] *= 2; + if (i % 100 == 0) { + // Yield to the RTOS kernel here + taskYIELD(); + } + } + time_end = get_reference_time(); + + rtos_printf("stage_preemption_enabled: %d (microseconds) \n", (time_end - time_start) / 100); +} + +void data_pipeline_init( + void *input_app_data, + void *output_app_data) +{ + const int stage_count = 2; + + const pipeline_stage_t stages[] = { + (pipeline_stage_t)stage_preemption_disabled, + (pipeline_stage_t)stage_preemption_enabled, + }; + + const configSTACK_DEPTH_TYPE stage_stack_sizes[] = { + configMINIMAL_STACK_SIZE + RTOS_THREAD_STACK_SIZE(stage_preemption_disabled) + RTOS_THREAD_STACK_SIZE(data_pipeline_input_i), + configMINIMAL_STACK_SIZE + RTOS_THREAD_STACK_SIZE(stage_preemption_enabled) + RTOS_THREAD_STACK_SIZE(data_pipeline_output_i), + }; + + generic_pipeline_init((pipeline_input_t)data_pipeline_input_i, + (pipeline_output_t)data_pipeline_output_i, + input_app_data, + output_app_data, + stages, + (const size_t*) stage_stack_sizes, + appconfDATA_PIPELINE_TASK_PRIORITY, + stage_count); +} + +#endif /* ON_TILE(1)*/ diff --git a/examples/freertos/xscope_fileio/src/fileio/xscope_fileio_task.c b/examples/freertos/xscope_fileio/src/fileio/xscope_fileio_task.c new file mode 100644 index 000000000..e8bf401c8 --- /dev/null +++ b/examples/freertos/xscope_fileio/src/fileio/xscope_fileio_task.c @@ -0,0 +1,202 @@ +// Copyright (c) 2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#include +#include +#include +#include + +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +#include "soc_xscope_host.h" + +#include "app_conf.h" +#include "platform/driver_instances.h" +#include "fileio/xscope_fileio_task.h" +#include "xscope_io_device.h" +#include "wav_utils.h" + +static TaskHandle_t fileio_task_handle; +static QueueHandle_t fileio_queue; + +static xscope_file_t infile; +static xscope_file_t outfile; + +#if ON_TILE(XSCOPE_HOST_IO_TILE) +static SemaphoreHandle_t mutex_xscope_fileio; + +void xscope_fileio_lock_alloc(void) { + mutex_xscope_fileio = xSemaphoreCreateMutex(); + xassert(mutex_xscope_fileio); +} + +void xscope_fileio_lock_acquire(void) { + xSemaphoreTake(mutex_xscope_fileio, portMAX_DELAY); +} + +void xscope_fileio_lock_release(void) { + xSemaphoreGive(mutex_xscope_fileio); +} + +void init_xscope_host_data_user_cb(chanend_t c_host) { + xscope_io_init(c_host); +} +#endif + +size_t xscope_fileio_tx_to_host(uint8_t *buf, size_t len_bytes) { + size_t ret = 0; + xQueueSend(fileio_queue, buf, portMAX_DELAY); + + return ret; +} + +size_t xscope_fileio_rx_from_host(void *input_app_data, int8_t **input_data_frame, size_t frame_count) { + + size_t bytes_received = 0; + bytes_received = rtos_intertile_rx_len( + intertile_ctx, + appconfEXAMPLE_DATA_PORT, + portMAX_DELAY); + + xassert(bytes_received == frame_count); + + rtos_intertile_rx_data( + intertile_ctx, + input_data_frame, + bytes_received); + + return bytes_received; +} + +void xscope_fileio_user_done(void) { + xTaskNotifyGive(fileio_task_handle); +} + +/* This task reads the input file in chunks and sends it through the data pipeline + * After reading the entire file, it will wait until the user has confirmed + * all writing is complete before closing files. + */ + /* NOTE: + * xscope fileio uses events. Only xscope_fread() currently, but wrapping + * all calls just in case */ +void xscope_fileio(void *arg) { + (void) arg; + int state = 0; + wav_header input_header_struct, output_header_struct; + unsigned input_header_size; + unsigned frame_count; + unsigned block_count; + uint8_t in_buf[appconfDATA_FRAME_SIZE_BYTES]; + uint8_t out_buf[appconfDATA_FRAME_SIZE_BYTES]; + size_t bytes_read = 0; + + /* Wait until xscope_fileio is initialized */ + while(xscope_fileio_is_initialized() == 0) { + vTaskDelay(pdMS_TO_TICKS(1)); + } + + fileio_queue = xQueueCreate(1, appconfDATA_FRAME_SIZE_BYTES); + + rtos_printf("Open test files\n"); + state = rtos_osal_critical_enter(); + { + infile = xscope_open_file(appconfINPUT_FILENAME, "rb"); + outfile = xscope_open_file(appconfOUTPUT_FILENAME, "wb"); + // 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); + } + xscope_fseek(&infile, input_header_size, SEEK_SET); + } + rtos_osal_critical_exit(state); + + // Ensure 32bit wav file + if(input_header_struct.bit_depth != 32) + { + rtos_printf("Error: unsupported wav bit depth (%d) for %s file. Only 32 supported\n", input_header_struct.bit_depth, appconfINPUT_FILENAME); + _Exit(1); + } + // Ensure input wav file contains correct number of channels + if(input_header_struct.num_channels != appconfMAX_CHANNELS){ + rtos_printf("Error: wav num channels(%d) does not match (%u)\n", input_header_struct.num_channels, appconfMAX_CHANNELS); + _Exit(1); + } + + // Calculate number of frames in the wav file + frame_count = wav_get_num_frames(&input_header_struct); + block_count = frame_count / appconfFRAME_ADVANCE; + + // Create output wav file + wav_form_header(&output_header_struct, + input_header_struct.audio_format, + appconfMAX_CHANNELS, + input_header_struct.sample_rate, + input_header_struct.bit_depth, + block_count*appconfFRAME_ADVANCE); + + xscope_fwrite(&outfile, (uint8_t*)(&output_header_struct), WAV_HEADER_BYTES); + + // ensure the write above has time to complete before performing any reads + vTaskDelay(pdMS_TO_TICKS(1000)); + + // Iterate over frame blocks and send the data to the first pipeline stage on tile[1] + for(unsigned b=0; b + +void xscope_fileio_tasks_create(unsigned priority, void* app_data); + +/* Signal to fileio that the application is done and files can be closed */ +void xscope_fileio_user_done(void); + +/* Send len_bytes + * returns number of bytes sent */ +size_t xscope_fileio_tx_to_host(uint8_t *buf, size_t len_bytes); + +size_t xscope_fileio_rx_from_host(void *input_app_data, int8_t **input_data_frame, size_t frame_count); + +#endif /* XSCOPE_FILEIO_TASK_H_ */ diff --git a/examples/freertos/xscope_fileio/src/main.c b/examples/freertos/xscope_fileio/src/main.c new file mode 100644 index 000000000..60ffe8814 --- /dev/null +++ b/examples/freertos/xscope_fileio/src/main.c @@ -0,0 +1,127 @@ +// Copyright (c) 2020-2022 XMOS LIMITED. This Software is subject to the terms of the +// XMOS Public License: Version 1 + +#include +#include +#include + +/* FreeRTOS headers */ +#include "FreeRTOS.h" +#include "task.h" +#include "stream_buffer.h" +#include "queue.h" + +/* Library headers */ +#include "rtos_printf.h" + +/* App headers */ +#include "app_conf.h" +#include "platform/platform_init.h" +#include "platform/driver_instances.h" +#include "fileio/xscope_fileio_task.h" +#include "data_pipeline.h" + +void data_pipeline_input( + void *input_app_data, + int8_t **input_data_frame, + size_t frame_count) +{ + (void) input_app_data; + +#if (DATA_TRANSPORT_METHOD == XSCOPE_FILEIO) + xscope_fileio_rx_from_host(input_app_data, input_data_frame, frame_count); +#endif +} + +int data_pipeline_output( + void *output_app_data, + int8_t **output_data_frame, + size_t frame_count) +{ + (void) output_app_data; + +#if (DATA_TRANSPORT_METHOD == XSCOPE_FILEIO) + (void) xscope_fileio_tx_to_host((uint8_t*)output_data_frame, frame_count); +#endif + + return DATA_PIPELINE_FREE_FRAME; +} + +void vApplicationMallocFailedHook(void) +{ + rtos_printf("Malloc Failed on tile %d!\n", THIS_XCORE_TILE); + xassert(0); + for(;;); +} + +static void mem_analysis(void) +{ + for (;;) { + rtos_printf("Tile[%d]:\n\tMinimum heap free: %d\n\tCurrent heap free: %d\n", THIS_XCORE_TILE, xPortGetMinimumEverFreeHeapSize(), xPortGetFreeHeapSize()); + vTaskDelay(pdMS_TO_TICKS(5000)); + } +} + +void startup_task(void *arg) +{ + rtos_printf("Startup task running from tile %d on core %d\n", THIS_XCORE_TILE, portGET_CORE_ID()); + + platform_start(); + +#if (DATA_TRANSPORT_METHOD == XSCOPE_FILEIO) +#if ON_TILE(XSCOPE_HOST_IO_TILE) + xscope_fileio_tasks_create(appconfXSCOPE_IO_TASK_PRIORITY, NULL); +#endif +#endif + + data_pipeline_init(NULL, NULL); + + mem_analysis(); + /* + * TODO: Watchdog? + */ +} + +void vApplicationMinimalIdleHook(void) +{ + rtos_printf("idle hook on tile %d core %d\n", THIS_XCORE_TILE, rtos_core_id_get()); + asm volatile("waiteu"); +} + +static void tile_common_init(chanend_t c) +{ + platform_init(c); + chanend_free(c); + + xTaskCreate((TaskFunction_t) startup_task, + "startup_task", + RTOS_THREAD_STACK_SIZE(startup_task), + NULL, + appconfSTARTUP_TASK_PRIORITY, + NULL); + + rtos_printf("start scheduler on tile %d\n", THIS_XCORE_TILE); + vTaskStartScheduler(); +} + +#if ON_TILE(0) +void main_tile0(chanend_t c0, chanend_t c1, chanend_t c2, chanend_t c3) +{ + (void) c0; + (void) c2; + (void) c3; + + tile_common_init(c1); +} +#endif + +#if ON_TILE(1) +void main_tile1(chanend_t c0, chanend_t c1, chanend_t c2, chanend_t c3) +{ + (void) c1; + (void) c2; + (void) c3; + + tile_common_init(c0); +} +#endif diff --git a/examples/freertos/xscope_fileio/src/wav/wav_utils.c b/examples/freertos/xscope_fileio/src/wav/wav_utils.c new file mode 100644 index 000000000..21cf9ed73 --- /dev/null +++ b/examples/freertos/xscope_fileio/src/wav/wav_utils.c @@ -0,0 +1,139 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#include +#include +#include +#include +#include +#include + + +#include "FreeRTOS.h" + +#include "wav_utils.h" + + +#define RIFF_SECTION_SIZE (12) +#define FMT_SUBCHUNK_MIN_SIZE (24) +#define EXTENDED_FMT_GUID_SIZE (16) +static const char wav_default_header[WAV_HEADER_BYTES] = { + 0x52, 0x49, 0x46, 0x46, + 0x00, 0x00, 0x00, 0x00, + 0x57, 0x41, 0x56, 0x45, + 0x66, 0x6d, 0x74, 0x20, + 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x64, 0x61, 0x74, 0x61, + 0x00, 0x00, 0x00, 0x00, +}; + +int get_wav_header_details(xscope_file_t *input_file, wav_header *s, unsigned *header_size){ + //Assume file is already open here. First rewind. + xscope_fseek(input_file, 0, SEEK_SET); + //read riff header section (12 bytes) + xscope_fread(input_file, (uint8_t*)(&s->riff_header[0]), RIFF_SECTION_SIZE); + if(memcmp(s->riff_header, "RIFF", sizeof(s->riff_header)) != 0) + { + rtos_printf("Error: couldn't find RIFF: 0x%x, 0x%x, 0x%x, 0x%x\n", s->riff_header[0], s->riff_header[1], s->riff_header[2], s->riff_header[3]); + return 1; + } + + if(memcmp(s->wave_header, "WAVE", sizeof(s->wave_header)) != 0) + { + rtos_printf("Error: couldn't find WAVE:, 0x%x, 0x%x, 0x%x, 0x%x\n", s->wave_header[0], s->wave_header[1], s->wave_header[2], s->wave_header[3]); + return 1; + } + + xscope_fread(input_file, (uint8_t*)&s->fmt_header[0], FMT_SUBCHUNK_MIN_SIZE); + if(memcmp(s->fmt_header, "fmt ", sizeof(s->fmt_header)) != 0) + { + rtos_printf("Error: couldn't find fmt: 0x%x, 0x%x, 0x%x, 0x%x\n", s->fmt_header[0], s->fmt_header[1], s->fmt_header[2], s->fmt_header[3]); + return 1; + } + + unsigned fmt_subchunk_actual_size = s->fmt_chunk_size + sizeof(s->fmt_header) + sizeof(s->fmt_chunk_size); //fmt_chunk_size doesn't include the fmt_header(4) and size(4) bytes + unsigned fmt_subchunk_remaining_size = fmt_subchunk_actual_size - FMT_SUBCHUNK_MIN_SIZE; + + if(s->audio_format == (short)0xfffe) + { + //seek to the end of fmt subchunk and rewind 16bytes to the beginning of GUID + xscope_fseek(input_file, fmt_subchunk_remaining_size - EXTENDED_FMT_GUID_SIZE, SEEK_CUR); + //The first 2 bytes of GUID is the audio_format. + xscope_fread(input_file, (uint8_t *)&s->audio_format, sizeof(s->audio_format)); + //skip the rest of GUID + xscope_fseek(input_file, EXTENDED_FMT_GUID_SIZE - sizeof(s->audio_format), SEEK_CUR); + } + else + { + //go to the end of fmt subchunk + xscope_fseek(input_file, fmt_subchunk_remaining_size, SEEK_CUR); + } + if(s->audio_format != 1) + { + rtos_printf("Error: audio format(%d) is not PCM\n", s->audio_format); + return 1; + } + + //read header (4 bytes) for the next subchunk + xscope_fread(input_file, (uint8_t*)&s->data_header[0], sizeof(s->data_header)); + //if next subchunk is fact, read subchunk size and skip it + if(memcmp(s->data_header, "fact", sizeof(s->data_header)) == 0) + { + uint32_t chunksize; + xscope_fread(input_file, (uint8_t *)&chunksize, sizeof(s->data_bytes)); + xscope_fseek(input_file, chunksize, SEEK_CUR); + xscope_fread(input_file, (uint8_t*)(&s->data_header[0]), sizeof(s->data_header)); + } + //only thing expected at this point is the 'data' subchunk. Throw error if not found. + if(memcmp(s->data_header, "data", sizeof(s->data_header)) != 0) + { + rtos_printf("Error: couldn't find data: 0x%x, 0x%x, 0x%x, 0x%x\n", s->data_header[0], s->data_header[1], s->data_header[2], s->data_header[3]); + return 1; + } + //read data subchunk size. + xscope_fread(input_file, (uint8_t *)&s->data_bytes, sizeof(s->data_bytes)); + *header_size = xscope_ftell(input_file); //total file size should be header_size + data_bytes + //No need to close file - handled by caller + + return 0; +} + +int wav_form_header(wav_header *header, + short audio_format, + short num_channels, + int sample_rate, + short bit_depth, + int num_frames){ + memcpy((char*)header, wav_default_header, WAV_HEADER_BYTES); + + header->audio_format = audio_format; + header->num_channels = num_channels; + header->sample_rate = sample_rate; + header->bit_depth = bit_depth; + + header->byte_rate = sample_rate*bit_depth*num_channels/8; + + header->sample_alignment = num_channels* (bit_depth/8); + int data_bytes = num_frames * num_channels * (bit_depth/8); + header->data_bytes = data_bytes; + header->wav_size = data_bytes + WAV_HEADER_BYTES - 8; + + return 0; +} + +unsigned wav_get_num_bytes_per_frame(const wav_header *s){ + int bytes_per_sample = s->bit_depth/8; + return (unsigned)(bytes_per_sample * s->num_channels); +} + +int wav_get_num_frames(const wav_header *s){ + unsigned bytes_per_frame = wav_get_num_bytes_per_frame(s); + return s->data_bytes / bytes_per_frame; +} + +long wav_get_frame_start(const wav_header *s, unsigned frame_number, uint32_t wavheader_size){ + return wavheader_size + frame_number * wav_get_num_bytes_per_frame(s); +} diff --git a/examples/freertos/xscope_fileio/src/wav/wav_utils.h b/examples/freertos/xscope_fileio/src/wav/wav_utils.h new file mode 100644 index 000000000..3da492831 --- /dev/null +++ b/examples/freertos/xscope_fileio/src/wav/wav_utils.h @@ -0,0 +1,48 @@ +// Copyright 2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. +#ifndef WAV_UTILS_H +#define WAV_UTILS_H + +#include + +#include "xscope_io_device.h" + +#define WAV_HEADER_BYTES 44 + +typedef struct wav_header { + // RIFF Header + char riff_header[4]; // Should be "RIFF" + int wav_size; // File size - 8 = data_bytes + WAV_HEADER_BYTES - 8 + char wave_header[4]; // Should be "WAVE" + + // Format Subsection + char fmt_header[4]; // Should be "fmt " + int fmt_chunk_size; // Size of the rest of this subchunk + short audio_format; + short num_channels; + int sample_rate; + int byte_rate; // sample_rate * num_channels * (bit_depth/8) + short sample_alignment; // num_channels * (bit_depth/8) + short bit_depth; // bits per sample + + // Data Subsection + char data_header[4]; // Should be "data" + int data_bytes; // frame count * num_channels * (bit_depth/8) +} wav_header; + +int get_wav_header_details(xscope_file_t *input_file, wav_header *s, unsigned *header_size); + +int wav_form_header(wav_header *header, + short audio_format, + short num_channels, + int sample_rate, + short bit_depth, + int num_frames); + +unsigned wav_get_num_bytes_per_frame(const wav_header *s); + +int wav_get_num_frames(const wav_header *s); + +long wav_get_frame_start(const wav_header *s, unsigned frame_number, uint32_t wavheader_size); + +#endif // WAV_UTILS_H diff --git a/examples/freertos/xscope_fileio/xscope_fileio.cmake b/examples/freertos/xscope_fileio/xscope_fileio.cmake new file mode 100644 index 000000000..e524a3fe2 --- /dev/null +++ b/examples/freertos/xscope_fileio/xscope_fileio.cmake @@ -0,0 +1,89 @@ +#********************** +# 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/wav + ${CMAKE_CURRENT_LIST_DIR}/src/data_pipeline/api +) + +#********************** +# Flags +#********************** +set(APP_COMPILER_FLAGS + -Os + -g + -report + -fxscope + -mcmodel=large + -Wno-xcore-fptrgroup + ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn +) + +set(APP_COMPILE_DEFINITIONS + DEBUG_PRINT_ENABLE=1 + PLATFORM_USES_TILE_0=1 + PLATFORM_USES_TILE_1=1 + XUD_CORE_CLOCK=600 + + DATA_TRANSPORT_METHOD=XSCOPE_FILEIO + XSCOPE_HOST_IO_ENABLED=1 + XSCOPE_HOST_IO_TILE=0 +) + +set(APP_LINK_OPTIONS + -report + ${CMAKE_CURRENT_LIST_DIR}/src/config.xscope + ${CMAKE_CURRENT_LIST_DIR}/XCORE-AI-EXPLORER.xn +) + +set(APP_COMMON_LINK_LIBRARIES + sdk::xscope_fileio + rtos::bsp_config::xcore_ai_explorer + core::xs3_math +) + +#********************** +# Tile Targets +#********************** +set(TARGET_NAME tile0_example_freertos_xscope_fileio) +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 ${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_freertos_xscope_fileio) +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 ${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_freertos_xscope_fileio tile0_example_freertos_xscope_fileio tile1_example_freertos_xscope_fileio 1) + +#********************** +# Create run and debug targets +#********************** +add_custom_target(run_example_freertos_xscope_fileio + COMMAND xrun --xscope-realtime --xscope-port localhost:12345 example_freertos_xscope_fileio.xe + DEPENDS example_freertos_xscope_fileio + COMMENT + "Run application" + VERBATIM +) + +create_debug_target(example_freertos_xscope_fileio) +create_flash_app_target(example_freertos_xscope_fileio) +create_install_target(example_freertos_xscope_fileio) diff --git a/index.rst b/index.rst index 2858d4f8d..e73cbf751 100644 --- a/index.rst +++ b/index.rst @@ -14,6 +14,7 @@ This is the user guide for the `XCORE Software Development Kit bash test/examples/run_freertos_explorer_board_tests.sh - bash test/examples/run_freertos_dispatcher_tests.sh bash test/examples/run_freertos_l2_cache_tests.sh + bash test/examples/run_freertos_tracealyzer_tests.sh Bare-metal Examples diff --git a/test/examples/run_freertos_dispatcher_tests.sh b/test/examples/run_freertos_dispatcher_tests.sh deleted file mode 100755 index aeb85da2a..000000000 --- a/test/examples/run_freertos_dispatcher_tests.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -set -e - -XCORE_SDK_ROOT=`git rev-parse --show-toplevel` -source ${XCORE_SDK_ROOT}/tools/ci/helper_functions.sh - -BUILD_DIR="build" -APPLICATION="example_freertos_dispatcher" - -if [ ! -z "$1" ] -then - ADAPTER_ID="--adapter-id $1" -fi - -TIMEOUT_EXE=$(get_timeout) -DURATION="10s" - -APP_XE=${BUILD_DIR}/${APPLICATION}.xe -APP_LOG=${APPLICATION}.log - -($TIMEOUT_EXE $DURATION xrun $ADAPTER_ID --xscope $APP_XE 2>&1 | tee $APP_LOG) - -# Search the log file for strings that indicate the app ran OK - -# Expect exactly one match found -result=$(grep -c "output matrix verified" $APP_LOG || true) - -if [ $result -ne 1 ]; then - echo "FAIL" - exit 1 -fi - -echo "PASS" diff --git a/test/examples/run_freertos_explorer_board_tests.sh b/test/examples/run_freertos_explorer_board_tests.sh index 68e12e0dd..32e887e6e 100755 --- a/test/examples/run_freertos_explorer_board_tests.sh +++ b/test/examples/run_freertos_explorer_board_tests.sh @@ -4,7 +4,7 @@ set -e XCORE_SDK_ROOT=`git rev-parse --show-toplevel` source ${XCORE_SDK_ROOT}/tools/ci/helper_functions.sh -BUILD_DIR="build" +BUILD_DIR="${XCORE_SDK_ROOT}/dist" APPLICATION="example_freertos_explorer_board" if [ ! -z "$1" ] diff --git a/test/examples/run_freertos_getting_started_tests.sh b/test/examples/run_freertos_getting_started_tests.sh index 7ed4c01a4..c0b9f7184 100755 --- a/test/examples/run_freertos_getting_started_tests.sh +++ b/test/examples/run_freertos_getting_started_tests.sh @@ -4,7 +4,7 @@ set -e XCORE_SDK_ROOT=`git rev-parse --show-toplevel` source ${XCORE_SDK_ROOT}/tools/ci/helper_functions.sh -BUILD_DIR="build" +BUILD_DIR="${XCORE_SDK_ROOT}/dist" APPLICATION="example_freertos_getting_started" if [ ! -z "$1" ] diff --git a/test/examples/run_freertos_l2_cache_tests.sh b/test/examples/run_freertos_l2_cache_tests.sh index 791f815e2..8c6bae890 100755 --- a/test/examples/run_freertos_l2_cache_tests.sh +++ b/test/examples/run_freertos_l2_cache_tests.sh @@ -4,7 +4,7 @@ set -e XCORE_SDK_ROOT=`git rev-parse --show-toplevel` source ${XCORE_SDK_ROOT}/tools/ci/helper_functions.sh -BUILD_DIR="build" +BUILD_DIR="${XCORE_SDK_ROOT}/dist" APPLICATION="example_freertos_l2_cache" if [ ! -z "$1" ] diff --git a/test/examples/run_freertos_tracealyzer_tests.sh b/test/examples/run_freertos_tracealyzer_tests.sh new file mode 100755 index 000000000..1fd0806ec --- /dev/null +++ b/test/examples/run_freertos_tracealyzer_tests.sh @@ -0,0 +1,75 @@ +#!/bin/bash +set -e + +XCORE_SDK_ROOT=`git rev-parse --show-toplevel` +source ${XCORE_SDK_ROOT}/tools/ci/helper_functions.sh + +BUILD_DIR="${XCORE_SDK_ROOT}/dist" +APPLICATION="example_freertos_tracealyzer" + +if [ ! -z "$1" ] +then + ADAPTER_ID="--adapter-id $1" +fi + +TIMEOUT_EXE=$(get_timeout) +DURATION="10s" + +APP_XE=${BUILD_DIR}/${APPLICATION}.xe +APP_TRACE=${BUILD_DIR}/${APPLICATION}_trace +APP_LOG=${APPLICATION}.log + +($TIMEOUT_EXE $DURATION xrun $ADAPTER_ID --xscope-file $APP_TRACE $APP_XE 2>&1 | tee $APP_LOG) + +# Search the log file for strings that indicate the app ran OK + +# Expect exactly one match found +result_main_task=$(grep -c "Entered main process" $APP_LOG || true) +result_subtask0=$(grep -c "Entered subprocess task (0)" $APP_LOG || true) +result_subtask1=$(grep -c "Entered subprocess task (1)" $APP_LOG || true) +result_subtask2=$(grep -c "Entered subprocess task (2)" $APP_LOG || true) +result_subtask3=$(grep -c "Entered subprocess task (3)" $APP_LOG || true) +result_subtask4=$(grep -c "Entered subprocess task (4)" $APP_LOG || true) +result_subtask5=$(grep -c "Entered subprocess task (5)" $APP_LOG || true) +result_subtask6=$(grep -c "Entered subprocess task (6)" $APP_LOG || true) +result_subtask7=$(grep -c "Entered subprocess task (7)" $APP_LOG || true) +result_gpio_task=$(grep -c "Entered gpio task" $APP_LOG || true) + +# Expect one or more matches found +result_hello_tile0=$(grep -c "Hello from tile 0" $APP_LOG || true) +result_hello_tile1=$(grep -c "Hello from tile 1" $APP_LOG || true) + +# Define a set of regex components to find the VCD line containing the PSF +# header. This header descibes the tracealyzer version/configuration and +# serves as a basic verification step that the FreeRTOS example has been +# configured to run tracealyzer. +PSF_HEADER_LEN="l32" +PSF_BOM="00465350" +PSF_FORMAT_VER="0a00" +PSF_PLTFM_ID="a11a" +PSF_OPTIONS="[0-9a-fA-F]\{8\}" +PSF_NUM_CORES="[0-9a-fA-F]\{8\}" +PSF_ISR_TAIL_CHAIN_THRES="[0-9a-fA-F]\{8\}" +PSF_PLTFM_CFG="4672656552544f53" # "FreeRTOS" +PSF_PLTFM_CFG_VER="[0-9a-fA-F]\{8\}" +PSF_PROBE="0" + +PSF_HEADER_REGEX="^$PSF_HEADER_LEN $PSF_BOM$PSF_FORMAT_VER\ +$PSF_PLTFM_ID$PSF_OPTIONS$PSF_NUM_CORES$PSF_ISR_TAIL_CHAIN_THRES\ +$PSF_PLTFM_CFG$PSF_PLTFM_CFG_VER $PSF_PROBE" + +# Check for the PSF header near the beginning of the VCD file. +# Only one occurance of this entry should be detected. +result_tracealyzer=$(head -n 10 $APP_TRACE.vcd | grep -c "$PSF_HEADER_REGEX") + +if [ $result_hello_tile0 -le 1 ] || [ $result_hello_tile1 -le 1 ] || + [ $result_main_task -ne 1 ] || + [ $result_subtask0 -ne 1 ] || [ $result_subtask1 -ne 1 ] || [ $result_subtask2 -ne 1 ] || + [ $result_subtask3 -ne 1 ] || [ $result_subtask4 -ne 1 ] || [ $result_subtask5 -ne 1 ] || + [ $result_subtask6 -ne 1 ] || [ $result_subtask7 -ne 1 ] || [ $result_gpio_task -ne 1 ] || + [ $result_tracealyzer -ne 1 ]; then + echo "FAIL" + exit 1 +fi + +echo "PASS" diff --git a/test/rtos_drivers/clock_control/run_tests.sh b/test/rtos_drivers/clock_control/run_tests.sh index cd6e92a6e..253691b5b 100755 --- a/test/rtos_drivers/clock_control/run_tests.sh +++ b/test/rtos_drivers/clock_control/run_tests.sh @@ -10,18 +10,20 @@ UNAME=$(uname) rm -rf testing mkdir testing REPORT=testing/test.rpt -FIRMWARE=clock_control_test.xe +FIRMWARE=test_rtos_driver_clock_control_test.xe TIMEOUT_S=60 rm -f ${REPORT} +XCORE_SDK_ROOT=`git rev-parse --show-toplevel` + echo "****************" echo "* Run Tests *" echo "****************" if [ "$UNAME" == "Linux" ] ; then - timeout ${TIMEOUT_S}s xrun --xscope bin/${FIRMWARE} 2>&1 | tee -a ${REPORT} + timeout ${TIMEOUT_S}s xrun --xscope ${XCORE_SDK_ROOT}/dist/${FIRMWARE} 2>&1 | tee -a ${REPORT} elif [ "$UNAME" == "Darwin" ] ; then - gtimeout ${TIMEOUT_S}s xrun --xscope bin/${FIRMWARE} 2>&1 | tee -a ${REPORT} + gtimeout ${TIMEOUT_S}s xrun --xscope ${XCORE_SDK_ROOT}/dist/${FIRMWARE} 2>&1 | tee -a ${REPORT} fi echo "****************" diff --git a/test/rtos_drivers/hil/hil.cmake b/test/rtos_drivers/hil/hil.cmake index 0dc83b7a8..db112a274 100644 --- a/test/rtos_drivers/hil/hil.cmake +++ b/test/rtos_drivers/hil/hil.cmake @@ -5,7 +5,7 @@ set(INTERTILE_TEST 1) set(I2C_TEST 1) set(GPIO_TEST 1) set(SWMEM_TEST 1) -set(QSPI_FLASH_TEST 1) +set(QSPI_FLASH_TEST 0) ## Will fail on Explorer 2V0 due to custom flash part set(I2S_TEST 1) set(MIC_ARRAY_TEST 1) diff --git a/test/rtos_drivers/hil/run_tests.sh b/test/rtos_drivers/hil/run_tests.sh index 39152df30..ed1c05f58 100755 --- a/test/rtos_drivers/hil/run_tests.sh +++ b/test/rtos_drivers/hil/run_tests.sh @@ -10,23 +10,25 @@ UNAME=$(uname) rm -rf testing mkdir testing REPORT=testing/test.rpt -FIRMWARE=rtos_drivers.xe +FIRMWARE=test_rtos_driver_hil.xe TIMEOUT_S=60 rm -f ${REPORT} +XCORE_SDK_ROOT=`git rev-parse --show-toplevel` + echo "****************" echo "* Run Tests *" echo "****************" if [ "$UNAME" == "Linux" ] ; then - timeout ${TIMEOUT_S}s xrun --xscope bin/${FIRMWARE} 2>&1 | tee -a ${REPORT} + timeout ${TIMEOUT_S}s xrun --xscope ${XCORE_SDK_ROOT}/dist/${FIRMWARE} 2>&1 | tee -a ${REPORT} elif [ "$UNAME" == "Darwin" ] ; then - gtimeout ${TIMEOUT_S}s xrun --xscope bin/${FIRMWARE} 2>&1 | tee -a ${REPORT} + gtimeout ${TIMEOUT_S}s xrun --xscope ${XCORE_SDK_ROOT}/dist/${FIRMWARE} 2>&1 | tee -a ${REPORT} fi echo "****************" echo "* Parse Result *" echo "****************" -python ${XCORE_SDK_PATH}/test/rtos_drivers/python/parse_test_output.py testing/test.rpt -outfile="testing/test_results" --print_test_results --verbose +python ${XCORE_SDK_ROOT}/test/rtos_drivers/python/parse_test_output.py testing/test.rpt -outfile="testing/test_results" --print_test_results --verbose pytest diff --git a/test/rtos_drivers/hil/src/app_conf.h b/test/rtos_drivers/hil/src/app_conf.h index 7656353a0..c1dd72929 100644 --- a/test/rtos_drivers/hil/src/app_conf.h +++ b/test/rtos_drivers/hil/src/app_conf.h @@ -27,10 +27,10 @@ #define MIC_ARRAY_RPC_HOST_TASK_PRIORITY (configMAX_PRIORITIES/2) #define I2C_SLAVE_ISR_CORE 4 -#define I2C_SLAVE_CORE_MASK (1 << 1) +#define I2C_SLAVE_CORE_MASK (1 << 2) #define I2C_SLAVE_ADDR 0x7A -#define MIC_ARRAY_CORE_MASK (1 << 2) +#define MIC_ARRAY_CORE_MASK (1 << 3) #define I2S_MASTER_CORE_MASK (1 << 6) #define I2S_SLAVE_CORE_MASK (1 << 6) @@ -44,11 +44,11 @@ #define I2S_MASTER_SEND_BUF_SIZE (I2S_FRAME_LEN * 2) #define I2S_SLAVE_RECV_BUF_SIZE (I2S_FRAME_LEN * 2) #define I2S_SLAVE_SEND_BUF_SIZE (I2S_FRAME_LEN * 2) -#define I2S_MASTER_ISR_CORE (0) -#define I2S_SLAVE_ISR_CORE (0) +#define I2S_MASTER_ISR_CORE (1) +#define I2S_SLAVE_ISR_CORE (1) #define MIC_ARRAY_TEST_AUDIO_SAMPLE_RATE 16000 -#define MIC_ARRAY_ISR_CORE 0 +#define MIC_ARRAY_ISR_CORE 1 #define MIC_ARRAY_CHAN_PAIRS 2 #define MIC_ARRAY_FRAME_LEN 256 #define MIC_ARRAY_TEST_ITERS 100 diff --git a/test/rtos_drivers/hil/src/board_init.c b/test/rtos_drivers/hil/src/board_init.c index 3eb31bb86..2e2fdc7b5 100644 --- a/test/rtos_drivers/hil/src/board_init.c +++ b/test/rtos_drivers/hil/src/board_init.c @@ -98,6 +98,29 @@ void board_tile0_init( 0, 100); + /* Manual parameters required for Explorer Board 2V0 */ + qspi_flash_ctx->ctx.sfdp_skip = true; + qspi_flash_ctx->ctx.sfdp_supported = false; + qspi_flash_ctx->ctx.page_size_bytes = 256; + qspi_flash_ctx->ctx.page_count = 16384; + qspi_flash_ctx->ctx.flash_size_kbytes = 4096; + qspi_flash_ctx->ctx.address_bytes = 3; + qspi_flash_ctx->ctx.erase_info[0].size_log2 = 12; + qspi_flash_ctx->ctx.erase_info[0].cmd = 0xEEFEEEEE; + qspi_flash_ctx->ctx.erase_info[1].size_log2 = 15; + qspi_flash_ctx->ctx.erase_info[1].cmd = 0xEFEFEEFE; + qspi_flash_ctx->ctx.erase_info[2].size_log2 = 16; + qspi_flash_ctx->ctx.erase_info[2].cmd = 0xFFEFFEEE; + qspi_flash_ctx->ctx.erase_info[3].size_log2 = 0; + qspi_flash_ctx->ctx.erase_info[3].cmd = 0; + qspi_flash_ctx->ctx.busy_poll_cmd = 0xEEEEEFEF; + qspi_flash_ctx->ctx.busy_poll_bit = 0; + qspi_flash_ctx->ctx.busy_poll_ready_value = 0; + qspi_flash_ctx->ctx.qe_reg = 2; + qspi_flash_ctx->ctx.qe_bit = 1; + qspi_flash_ctx->ctx.sr2_read_cmd = 0xEEFFEFEF; + qspi_flash_ctx->ctx.sr2_write_cmd = 0xEEEEEEEE; + rtos_qspi_flash_init( qspi_flash_ctx, XS1_CLKBLK_2, diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/i2c_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/i2c_test.c index 8fc836288..1186c517a 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/i2c_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/i2c_test.c @@ -69,12 +69,40 @@ static void i2c_slave_tx_done(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *da i2c_printf("SLAVE missing i2c_slave_tx_done callback on test %d", test_ctx->cur_test); } } + +RTOS_I2C_SLAVE_RX_BYTE_CHECK_CALLBACK_ATTR +void i2c_slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + if (test_ctx->slave_rx_check_byte[test_ctx->cur_test] != NULL) + { + I2C_SLAVE_RX_BYTE_CHECK_ATTR i2c_slave_rx_byte_check_cb_t fn; + fn = test_ctx->slave_rx_check_byte[test_ctx->cur_test]; + fn(ctx, app_data, data, cur_status); + } else { + i2c_printf("SLAVE missing slave_rx_check_byte callback on test %d", test_ctx->cur_test); + } +} + +RTOS_I2C_SLAVE_WRITE_ADDR_REQUEST_CALLBACK_ATTR +void i2c_slave_write_addr_req(rtos_i2c_slave_t *ctx, void *app_data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + if (test_ctx->slave_write_addr_req[test_ctx->cur_test] != NULL) + { + I2C_SLAVE_WRITE_ADDR_REQ_ATTR i2c_slave_write_addr_req_cb_t fn; + fn = test_ctx->slave_write_addr_req[test_ctx->cur_test]; + fn(ctx, app_data, cur_status); + } else { + i2c_printf("SLAVE missing slave_write_addr_req callback on test %d", test_ctx->cur_test); + } +} + #endif /* ON_TILE(1) */ static int run_i2c_tests(i2c_test_ctx_t *test_ctx, chanend_t c) { int retval = 0; - do { sync(c); @@ -116,6 +144,8 @@ static void start_i2c_devices(i2c_test_ctx_t *test_ctx) i2c_slave_rx, i2c_slave_tx_start, i2c_slave_tx_done, + i2c_slave_rx_byte_check, + i2c_slave_write_addr_req, I2C_SLAVE_ISR_CORE, configMAX_PRIORITIES-1); #endif diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/i2c_test.h b/test/rtos_drivers/hil/src/individual_tests/i2c/i2c_test.h index a8d818f24..86f5783c1 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/i2c_test.h +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/i2c_test.h @@ -10,10 +10,12 @@ #define I2C_MAX_TESTS 12 -#define I2C_MAIN_TEST_ATTR __attribute__((fptrgroup("rtos_test_i2c_main_test_fptr_grp"))) -#define I2C_SLAVE_RX_ATTR __attribute__((fptrgroup("rtos_test_i2c_slave_rx_fptr_grp"))) -#define I2C_SLAVE_TX_START_ATTR __attribute__((fptrgroup("rtos_test_i2c_slave_tx_start_fptr_grp"))) -#define I2C_SLAVE_TX_DONE_ATTR __attribute__((fptrgroup("rtos_test_i2c_slave_tx_done_fptr_grp"))) +#define I2C_MAIN_TEST_ATTR __attribute__((fptrgroup("rtos_test_i2c_main_test_fptr_grp"))) +#define I2C_SLAVE_RX_ATTR __attribute__((fptrgroup("rtos_test_i2c_slave_rx_fptr_grp"))) +#define I2C_SLAVE_TX_START_ATTR __attribute__((fptrgroup("rtos_test_i2c_slave_tx_start_fptr_grp"))) +#define I2C_SLAVE_TX_DONE_ATTR __attribute__((fptrgroup("rtos_test_i2c_slave_tx_done_fptr_grp"))) +#define I2C_SLAVE_RX_BYTE_CHECK_ATTR __attribute__((fptrgroup("rtos_test_i2c_slave_rx_byte_check_fptr_grp"))) +#define I2C_SLAVE_WRITE_ADDR_REQ_ATTR __attribute__((fptrgroup("rtos_test_i2c_slave_write_addr_check_fptr_grp"))) typedef struct i2c_test_ctx i2c_test_ctx_t; @@ -30,12 +32,16 @@ struct i2c_test_ctx { I2C_SLAVE_RX_ATTR void (*slave_rx[I2C_MAX_TESTS])(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_t len); I2C_SLAVE_TX_START_ATTR size_t (*slave_tx_start[I2C_MAX_TESTS])(rtos_i2c_slave_t *ctx, void *app_data, uint8_t **data); I2C_SLAVE_TX_DONE_ATTR void (*slave_tx_done[I2C_MAX_TESTS])(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_t len); + I2C_SLAVE_RX_BYTE_CHECK_ATTR void (*slave_rx_check_byte[I2C_MAX_TESTS])(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status); + I2C_SLAVE_WRITE_ADDR_REQ_ATTR void (*slave_write_addr_req[I2C_MAX_TESTS])(rtos_i2c_slave_t *ctx, void *app_data, i2c_slave_ack_t *cur_status); }; typedef int (*i2c_main_test_t)(i2c_test_ctx_t *ctx); typedef void (*i2c_slave_rx_t)(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_t len); typedef size_t (*i2c_slave_tx_start_t)(rtos_i2c_slave_t *ctx, void *app_data, uint8_t **data); typedef void (*i2c_slave_tx_done_t)(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_t len); +typedef void (*i2c_slave_rx_byte_check_cb_t)(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status); +typedef void (*i2c_slave_write_addr_req_cb_t)(rtos_i2c_slave_t *ctx, void *app_data, i2c_slave_ack_t *cur_status); int i2c_device_tests(rtos_i2c_master_t *i2c_master_ctx, rtos_i2c_slave_t *i2c_slave_ctx, chanend_t c); diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_read_multiple_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_read_multiple_test.c index 95f39042a..545abba5b 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_read_multiple_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_read_multiple_test.c @@ -146,6 +146,20 @@ static void slave_tx_done(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, test_slave_iters++; } +static int slave_byte_check = 0; + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); + int i = slave_byte_check % I2C_MASTER_READ_MULTIPLE_TEST_SIZE; + slave_byte_check++; + if (test_vector[test_slave_iters][i] != data) { + local_printf("SLAVE rx byte check failed"); + test_ctx->slave_success[test_ctx->cur_test] = -1; + } +} #endif void register_master_read_multiple_test(i2c_test_ctx_t *test_ctx) @@ -161,6 +175,8 @@ void register_master_read_multiple_test(i2c_test_ctx_t *test_ctx) test_ctx->slave_rx[this_test_num] = slave_rx; test_ctx->slave_tx_start[this_test_num] = slave_tx_start; test_ctx->slave_tx_done[this_test_num] = slave_tx_done; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(I2C_MASTER_TILE) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_read_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_read_test.c index 13da10eee..f24cec3c9 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_read_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_read_test.c @@ -127,6 +127,20 @@ static void slave_tx_done(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, test_slave_iters++; } +static int slave_byte_check = 0; + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); + int i = slave_byte_check % I2C_MASTER_READ_TEST_SIZE; + slave_byte_check++; + if (test_vector[test_slave_iters][i] != data) { + local_printf("SLAVE rx byte check failed"); + test_ctx->slave_success[test_ctx->cur_test] = -1; + } +} #endif void register_master_read_test(i2c_test_ctx_t *test_ctx) @@ -142,6 +156,8 @@ void register_master_read_test(i2c_test_ctx_t *test_ctx) test_ctx->slave_rx[this_test_num] = slave_rx; test_ctx->slave_tx_start[this_test_num] = slave_tx_start; test_ctx->slave_tx_done[this_test_num] = slave_tx_done; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(I2C_MASTER_TILE) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_reg_read_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_reg_read_test.c index 8d8adc4e8..66805e820 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_reg_read_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_reg_read_test.c @@ -148,6 +148,11 @@ static void slave_tx_done(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, } } +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); +} #endif void register_master_reg_read_test(i2c_test_ctx_t *test_ctx) @@ -163,6 +168,8 @@ void register_master_reg_read_test(i2c_test_ctx_t *test_ctx) test_ctx->slave_rx[this_test_num] = slave_rx; test_ctx->slave_tx_start[this_test_num] = slave_tx_start; test_ctx->slave_tx_done[this_test_num] = slave_tx_done; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(I2C_MASTER_TILE) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_reg_write_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_reg_write_test.c index 2a2ab457e..81c2adf97 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_reg_write_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_reg_write_test.c @@ -41,6 +41,7 @@ static reg_test_t test_vector[I2C_MASTER_REG_WRITE_TEST_ITER] = #if ON_TILE(I2C_SLAVE_TILE) static uint32_t test_slave_iters = 0; +static uint32_t test_slave_requests = 0; #endif I2C_MAIN_TEST_ATTR @@ -79,6 +80,11 @@ static int main_test(i2c_test_ctx_t *ctx) local_printf("SLAVE failed"); return -1; } + + if ((test_slave_requests) != test_slave_iters) { + local_printf("SLAVE failed"); + return -1; + } } #endif @@ -111,6 +117,19 @@ static void slave_rx(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_ test_slave_iters++; } + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); +} + +I2C_SLAVE_WRITE_ADDR_REQ_ATTR +static void slave_write_addr_req(rtos_i2c_slave_t *ctx, void *app_data, i2c_slave_ack_t *cur_status) +{ + test_slave_requests++; + local_printf("SLAVE write request %d", test_slave_requests); +} #endif void register_master_reg_write_test(i2c_test_ctx_t *test_ctx) @@ -124,6 +143,8 @@ void register_master_reg_write_test(i2c_test_ctx_t *test_ctx) #if ON_TILE(I2C_SLAVE_TILE) test_ctx->slave_rx[this_test_num] = slave_rx; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = slave_write_addr_req; #endif #if ON_TILE(I2C_MASTER_TILE) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_write_multiple_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_write_multiple_test.c index 691904361..2bc7a6eb2 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_write_multiple_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_write_multiple_test.c @@ -130,6 +130,25 @@ static void slave_rx(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_ test_slave_iters++; } + +static int slave_byte_check_iters = 0; +static int slave_byte_check = 0; + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); + int i = slave_byte_check % I2C_MASTER_WRITE_MULTIPLE_TEST_SIZE; + slave_byte_check++; + if (test_vector[slave_byte_check_iters][i] != data) { + local_printf("SLAVE rx byte check failed"); + test_ctx->slave_success[test_ctx->cur_test] = -1; + } + if ((slave_byte_check % I2C_MASTER_WRITE_MULTIPLE_TEST_SIZE) == 0) { + slave_byte_check_iters++; + } +} #endif void register_master_write_multiple_test(i2c_test_ctx_t *test_ctx) @@ -143,6 +162,8 @@ void register_master_write_multiple_test(i2c_test_ctx_t *test_ctx) #if ON_TILE(I2C_SLAVE_TILE) test_ctx->slave_rx[this_test_num] = slave_rx; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(I2C_MASTER_TILE) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_write_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_write_test.c index 6ff1af36a..579ae5146 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_write_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/local/master_write_test.c @@ -107,6 +107,21 @@ static void slave_rx(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_ test_slave_iters++; } + +static int slave_byte_check = 0; + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); + int i = slave_byte_check % I2C_MASTER_WRITE_TEST_SIZE; + slave_byte_check++; + if (test_vector[test_slave_iters][i] != data) { + local_printf("SLAVE rx byte check failed"); + test_ctx->slave_success[test_ctx->cur_test] = -1; + } +} #endif void register_master_write_test(i2c_test_ctx_t *test_ctx) @@ -120,6 +135,8 @@ void register_master_write_test(i2c_test_ctx_t *test_ctx) #if ON_TILE(I2C_SLAVE_TILE) test_ctx->slave_rx[this_test_num] = slave_rx; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(I2C_MASTER_TILE) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_read_multiple_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_read_multiple_test.c index d91a335d7..b807f9553 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_read_multiple_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_read_multiple_test.c @@ -146,6 +146,20 @@ static void slave_tx_done(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, test_slave_iters++; } +static int slave_byte_check = 0; + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); + int i = slave_byte_check % I2C_MASTER_READ_MULTIPLE_TEST_SIZE; + slave_byte_check++; + if (test_vector[test_slave_iters][i] != data) { + local_printf("SLAVE rx byte check failed"); + test_ctx->slave_success[test_ctx->cur_test] = -1; + } +} #endif void register_rpc_master_read_multiple_test(i2c_test_ctx_t *test_ctx) @@ -161,6 +175,8 @@ void register_rpc_master_read_multiple_test(i2c_test_ctx_t *test_ctx) test_ctx->slave_rx[this_test_num] = slave_rx; test_ctx->slave_tx_start[this_test_num] = slave_tx_start; test_ctx->slave_tx_done[this_test_num] = slave_tx_done; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(0) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_read_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_read_test.c index 47de79f41..c6dd54c28 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_read_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_read_test.c @@ -127,6 +127,20 @@ static void slave_tx_done(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, test_slave_iters++; } +static int slave_byte_check = 0; + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); + int i = slave_byte_check % I2C_MASTER_READ_TEST_SIZE; + slave_byte_check++; + if (test_vector[test_slave_iters][i] != data) { + local_printf("SLAVE rx byte check failed"); + test_ctx->slave_success[test_ctx->cur_test] = -1; + } +} #endif void register_rpc_master_read_test(i2c_test_ctx_t *test_ctx) @@ -142,6 +156,8 @@ void register_rpc_master_read_test(i2c_test_ctx_t *test_ctx) test_ctx->slave_rx[this_test_num] = slave_rx; test_ctx->slave_tx_start[this_test_num] = slave_tx_start; test_ctx->slave_tx_done[this_test_num] = slave_tx_done; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(0) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_reg_read_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_reg_read_test.c index 376803fc1..a3d64675b 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_reg_read_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_reg_read_test.c @@ -148,6 +148,11 @@ static void slave_tx_done(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, } } +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); +} #endif void register_rpc_master_reg_read_test(i2c_test_ctx_t *test_ctx) @@ -163,6 +168,8 @@ void register_rpc_master_reg_read_test(i2c_test_ctx_t *test_ctx) test_ctx->slave_rx[this_test_num] = slave_rx; test_ctx->slave_tx_start[this_test_num] = slave_tx_start; test_ctx->slave_tx_done[this_test_num] = slave_tx_done; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(0) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_reg_write_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_reg_write_test.c index e5d0e69be..a02d90bfd 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_reg_write_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_reg_write_test.c @@ -41,6 +41,7 @@ static reg_test_t test_vector[I2C_MASTER_REG_WRITE_TEST_ITER] = #if ON_TILE(I2C_SLAVE_TILE) static uint32_t test_slave_iters = 0; +static uint32_t test_slave_requests = 0; #endif I2C_MAIN_TEST_ATTR @@ -79,6 +80,11 @@ static int main_test(i2c_test_ctx_t *ctx) local_printf("SLAVE failed"); return -1; } + + if ((test_slave_requests) != test_slave_iters) { + local_printf("SLAVE failed"); + return -1; + } } #endif @@ -111,6 +117,19 @@ static void slave_rx(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_ test_slave_iters++; } + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); +} + +I2C_SLAVE_WRITE_ADDR_REQ_ATTR +static void slave_write_addr_req(rtos_i2c_slave_t *ctx, void *app_data, i2c_slave_ack_t *cur_status) +{ + test_slave_requests++; + local_printf("SLAVE write request %d", test_slave_requests); +} #endif void register_rpc_master_reg_write_test(i2c_test_ctx_t *test_ctx) @@ -124,6 +143,8 @@ void register_rpc_master_reg_write_test(i2c_test_ctx_t *test_ctx) #if ON_TILE(I2C_SLAVE_TILE) test_ctx->slave_rx[this_test_num] = slave_rx; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = slave_write_addr_req; #endif #if ON_TILE(0) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_write_multiple_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_write_multiple_test.c index b28eb51f9..5cc5b54e6 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_write_multiple_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_write_multiple_test.c @@ -130,6 +130,25 @@ static void slave_rx(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_ test_slave_iters++; } + +static int slave_byte_check_iters = 0; +static int slave_byte_check = 0; + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); + int i = slave_byte_check % I2C_MASTER_WRITE_MULTIPLE_TEST_SIZE; + slave_byte_check++; + if (test_vector[slave_byte_check_iters][i] != data) { + local_printf("SLAVE rx byte check failed"); + test_ctx->slave_success[test_ctx->cur_test] = -1; + } + if ((slave_byte_check % I2C_MASTER_WRITE_MULTIPLE_TEST_SIZE) == 0) { + slave_byte_check_iters++; + } +} #endif void register_rpc_master_write_multiple_test(i2c_test_ctx_t *test_ctx) @@ -143,6 +162,8 @@ void register_rpc_master_write_multiple_test(i2c_test_ctx_t *test_ctx) #if ON_TILE(I2C_SLAVE_TILE) test_ctx->slave_rx[this_test_num] = slave_rx; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(0) diff --git a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_write_test.c b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_write_test.c index 6cbd3ce8d..bca6039e2 100644 --- a/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_write_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/i2c/rpc/master_write_test.c @@ -107,6 +107,21 @@ static void slave_rx(rtos_i2c_slave_t *ctx, void *app_data, uint8_t *data, size_ test_slave_iters++; } + +static int slave_byte_check = 0; + +I2C_SLAVE_RX_BYTE_CHECK_ATTR +static void slave_rx_byte_check(rtos_i2c_slave_t *ctx, void *app_data, uint8_t data, i2c_slave_ack_t *cur_status) +{ + i2c_test_ctx_t *test_ctx = (i2c_test_ctx_t*)ctx->app_data; + local_printf("SLAVE rx byte check 0x%x status %d", data, *cur_status); + int i = slave_byte_check % I2C_MASTER_WRITE_TEST_SIZE; + slave_byte_check++; + if (test_vector[test_slave_iters][i] != data) { + local_printf("SLAVE rx byte check failed"); + test_ctx->slave_success[test_ctx->cur_test] = -1; + } +} #endif void register_rpc_master_write_test(i2c_test_ctx_t *test_ctx) @@ -120,6 +135,8 @@ void register_rpc_master_write_test(i2c_test_ctx_t *test_ctx) #if ON_TILE(I2C_SLAVE_TILE) test_ctx->slave_rx[this_test_num] = slave_rx; + test_ctx->slave_rx_check_byte[this_test_num] = slave_rx_byte_check; + test_ctx->slave_write_addr_req[this_test_num] = NULL; #endif #if ON_TILE(0) diff --git a/test/rtos_drivers/hil/src/individual_tests/qspi_flash/rpc/read_write_read_test.c b/test/rtos_drivers/hil/src/individual_tests/qspi_flash/rpc/read_write_read_test.c index f5a2a957c..a497121b6 100644 --- a/test/rtos_drivers/hil/src/individual_tests/qspi_flash/rpc/read_write_read_test.c +++ b/test/rtos_drivers/hil/src/individual_tests/qspi_flash/rpc/read_write_read_test.c @@ -46,7 +46,7 @@ static int read_write_read(rtos_qspi_flash_t *ctx, unsigned addr, size_t test_le { if (test_buf[i] != 0xFF) { - local_printf("Failed. rx_buf[%d]: Expected 0 got 0x%x", i, test_buf[i]); + local_printf("Failed. rx_buf[%d]: Expected 0xFF got 0x%x", i, test_buf[i]); rtos_osal_free(test_buf); return -1; } diff --git a/test/rtos_drivers/hil_add/hil_add.cmake b/test/rtos_drivers/hil_add/hil_add.cmake index e262b4e3f..7a5beb29c 100644 --- a/test/rtos_drivers/hil_add/hil_add.cmake +++ b/test/rtos_drivers/hil_add/hil_add.cmake @@ -2,7 +2,7 @@ # Individual tests #********************** set(SPI_TEST 1) -set(UART_TEST 1) +set(UART_TEST 0) # Appears to be broken #********************** # Gather Sources diff --git a/test/rtos_drivers/hil_add/run_tests.sh b/test/rtos_drivers/hil_add/run_tests.sh index 39152df30..fc1c71424 100755 --- a/test/rtos_drivers/hil_add/run_tests.sh +++ b/test/rtos_drivers/hil_add/run_tests.sh @@ -10,23 +10,25 @@ UNAME=$(uname) rm -rf testing mkdir testing REPORT=testing/test.rpt -FIRMWARE=rtos_drivers.xe +FIRMWARE=test_rtos_driver_hil_add.xe TIMEOUT_S=60 rm -f ${REPORT} +XCORE_SDK_ROOT=`git rev-parse --show-toplevel` + echo "****************" echo "* Run Tests *" echo "****************" if [ "$UNAME" == "Linux" ] ; then - timeout ${TIMEOUT_S}s xrun --xscope bin/${FIRMWARE} 2>&1 | tee -a ${REPORT} + timeout ${TIMEOUT_S}s xrun --xscope ${XCORE_SDK_ROOT}/dist/${FIRMWARE} 2>&1 | tee -a ${REPORT} elif [ "$UNAME" == "Darwin" ] ; then - gtimeout ${TIMEOUT_S}s xrun --xscope bin/${FIRMWARE} 2>&1 | tee -a ${REPORT} + gtimeout ${TIMEOUT_S}s xrun --xscope ${XCORE_SDK_ROOT}/dist/${FIRMWARE} 2>&1 | tee -a ${REPORT} fi echo "****************" echo "* Parse Result *" echo "****************" -python ${XCORE_SDK_PATH}/test/rtos_drivers/python/parse_test_output.py testing/test.rpt -outfile="testing/test_results" --print_test_results --verbose +python ${XCORE_SDK_ROOT}/test/rtos_drivers/python/parse_test_output.py testing/test.rpt -outfile="testing/test_results" --print_test_results --verbose pytest diff --git a/test/rtos_drivers/hil_add/src/app_conf.h b/test/rtos_drivers/hil_add/src/app_conf.h index 525930d2d..2dca1857a 100644 --- a/test/rtos_drivers/hil_add/src/app_conf.h +++ b/test/rtos_drivers/hil_add/src/app_conf.h @@ -14,8 +14,8 @@ #define SPI_TEST_CPOL 0 #define SPI_TEST_CPHA 0 -#define SPI_SLAVE_CORE_MASK (1 << 1) -#define SPI_SLAVE_ISR_CORE 0 +#define SPI_SLAVE_CORE_MASK (1 << 4) +#define SPI_SLAVE_ISR_CORE 5 #define SPI_TEST_BUF_SIZE 4096 diff --git a/test/rtos_drivers/hil_add/src/board_init.c b/test/rtos_drivers/hil_add/src/board_init.c index 329019a91..e88502418 100644 --- a/test/rtos_drivers/hil_add/src/board_init.c +++ b/test/rtos_drivers/hil_add/src/board_init.c @@ -36,12 +36,12 @@ void board_tile0_init( 0, /* CS pin is on bit 0 of the CS port */ SPI_MODE_0, spi_master_source_clock_ref, - 0, /* 50 MHz */ + 1, /* 50 MHz */ spi_master_sample_delay_2, 0, - 1, - 0, - 0); + 10000, + 10000, + 10000); rtos_spi_master_device_t *spi_devices_ctx[1] = {test_device_ctx}; diff --git a/test/rtos_drivers/hil_add/src/individual_tests/spi/local/slave_default_buffer_test.c b/test/rtos_drivers/hil_add/src/individual_tests/spi/local/slave_default_buffer_test.c new file mode 100644 index 000000000..b93dd62ba --- /dev/null +++ b/test/rtos_drivers/hil_add/src/individual_tests/spi/local/slave_default_buffer_test.c @@ -0,0 +1,224 @@ +// Copyright 2021-2022 XMOS LIMITED. +// This Software is subject to the terms of the XMOS Public Licence: Version 1. + +/* System headers */ +#include +#include + +/* FreeRTOS headers */ +#include "FreeRTOS.h" + +/* Library headers */ +#include "rtos_spi_master.h" +#include "rtos_spi_slave.h" + +/* App headers */ +#include "app_conf.h" +#include "individual_tests/spi/spi_test.h" + +static const char* test_name = "slave_default_buffer_test"; + +#define local_printf( FMT, ... ) spi_printf("%s|" FMT, test_name, ##__VA_ARGS__) + +#define SPI_MASTER_TILE 0 +#define SPI_SLAVE_TILE 1 + +#if ON_TILE(SPI_MASTER_TILE) || ON_TILE(SPI_SLAVE_TILE) +static uint8_t test_buf[SPI_TEST_BUF_SIZE] = {0}; +#endif + +#if ON_TILE(SPI_SLAVE_TILE) +/* Since callbacks aren't used for data transmission, just verify that they + * were called */ +static uint32_t xfer_done_called = 0; + +static uint8_t default_in_buf[SPI_TEST_BUF_SIZE] = {0}; +static size_t default_in_buf_len = SPI_TEST_BUF_SIZE; +static uint8_t default_out_buf[SPI_TEST_BUF_SIZE] = {0}; +static size_t default_out_buf_len = SPI_TEST_BUF_SIZE; +#endif + +SPI_MAIN_TEST_ATTR +static int main_test(spi_test_ctx_t *ctx) +{ + local_printf("Start"); + + #if ON_TILE(SPI_SLAVE_TILE) + { + uint8_t in_buf[SPI_TEST_BUF_SIZE] = {0}; + for(int i=0; ispi_slave_ctx, + default_in_buf, + SPI_TEST_BUF_SIZE, + default_out_buf, + SPI_TEST_BUF_SIZE); + + local_printf("SLAVE transaction"); + + spi_slave_xfer_prepare( + ctx->spi_slave_ctx, + in_buf, + SPI_TEST_BUF_SIZE, + test_buf, + SPI_TEST_BUF_SIZE); + + /* Setup handling response */ + uint8_t *rx_buf = NULL; + size_t rx_len = 0; + uint8_t *tx_buf = NULL; + size_t tx_len = 0; + + int ret = spi_slave_xfer_complete( + ctx->spi_slave_ctx, + (void**)&rx_buf, + &rx_len, + (void**)&tx_buf, + &tx_len, + pdMS_TO_TICKS(10000)); + + /* First time it should be user provided buffer */ + if (!((rx_buf == in_buf) && tx_buf == test_buf)) { + local_printf("SLAVE failed. Unexpected buffer. Expected user"); + return -1; + } + + if (ret != 0) + { + local_printf("SLAVE failed. Transfer timed out"); + return -1; + } + + if (rx_len != SPI_TEST_BUF_SIZE) { + local_printf("SLAVE failed. RX len got %u expected %u", rx_len, SPI_TEST_BUF_SIZE); + return -1; + } else if (tx_len != SPI_TEST_BUF_SIZE) { + local_printf("SLAVE failed. TX len got %u expected %u", tx_len, SPI_TEST_BUF_SIZE); + return -1; + } + + if (rx_buf == NULL) { + local_printf("SLAVE failed. rx_buf is NULL"); + return -1; + } else if (tx_buf == NULL) { + local_printf("SLAVE failed. tx_buf is NULL"); + return -1; + } + + for (int i=0; ispi_slave_ctx, + (void**)&rx_buf, + &rx_len, + (void**)&tx_buf, + &tx_len, + pdMS_TO_TICKS(10000)); + + /* Second time it should be default buffer */ + if (!((rx_buf == default_in_buf) && tx_buf == default_out_buf)) { + local_printf("SLAVE failed. Unexpected buffer. Expected default"); + return -1; + } + + vTaskDelay(pdMS_TO_TICKS(500)); + } + #endif + + #if ON_TILE(SPI_MASTER_TILE) + { + vTaskDelay(pdMS_TO_TICKS(100)); + + uint8_t in_buf[SPI_TEST_BUF_SIZE] = {0}; + uint8_t in_buf_default[SPI_TEST_BUF_SIZE] = {0}; + + /* Force a default buffer situation by the SPI slave */ + local_printf("MASTER transaction"); + rtos_spi_master_transaction_start(ctx->spi_device_ctx); + rtos_spi_master_transfer(ctx->spi_device_ctx, test_buf, in_buf, SPI_TEST_BUF_SIZE); + rtos_spi_master_transaction_end(ctx->spi_device_ctx); + local_printf("MASTER transaction"); + rtos_spi_master_transaction_start(ctx->spi_device_ctx); + rtos_spi_master_transfer(ctx->spi_device_ctx, test_buf, in_buf_default, SPI_TEST_BUF_SIZE); + rtos_spi_master_transaction_end(ctx->spi_device_ctx); + + /* Verify that in_buf == test_buf, and in_buf_default == the default SPI Slave buffer */ + for (int i=0; itest_cnt; + + local_printf("Register to test num %d", this_test_num); + + test_ctx->name[this_test_num] = (char*)test_name; + test_ctx->main_test[this_test_num] = main_test; + +#if ON_TILE(SPI_MASTER_TILE) || ON_TILE(SPI_SLAVE_TILE) + for (int i=0; islave_xfer_done[this_test_num] = slave_xfer_done; +#endif + + test_ctx->test_cnt++; +} + +#undef local_printf diff --git a/test/rtos_drivers/hil_add/src/individual_tests/spi/spi_test.c b/test/rtos_drivers/hil_add/src/individual_tests/spi/spi_test.c index a39d4889c..a958a26e6 100644 --- a/test/rtos_drivers/hil_add/src/individual_tests/spi/spi_test.c +++ b/test/rtos_drivers/hil_add/src/individual_tests/spi/spi_test.c @@ -94,6 +94,8 @@ static void register_spi_tests(spi_test_ctx_t *test_ctx) register_rpc_single_transaction_test(test_ctx); register_rpc_multiple_transaction_test(test_ctx); + + register_slave_default_buffer_test(test_ctx); } static void spi_init_tests(spi_test_ctx_t *test_ctx, rtos_spi_master_t *spi_master_ctx, rtos_spi_master_device_t *spi_device_ctx, rtos_spi_slave_t *spi_slave_ctx) diff --git a/test/rtos_drivers/hil_add/src/individual_tests/spi/spi_test.h b/test/rtos_drivers/hil_add/src/individual_tests/spi/spi_test.h index afb60095b..ba150807e 100644 --- a/test/rtos_drivers/hil_add/src/individual_tests/spi/spi_test.h +++ b/test/rtos_drivers/hil_add/src/individual_tests/spi/spi_test.h @@ -8,7 +8,7 @@ #define spi_printf( FMT, ... ) module_printf("SPI", FMT, ##__VA_ARGS__) -#define SPI_MAX_TESTS 4 +#define SPI_MAX_TESTS 5 #define SPI_MAIN_TEST_ATTR __attribute__((fptrgroup("rtos_test_spi_main_test_fptr_grp"))) #define SPI_SLAVE_XFER_DONE_ATTR __attribute__((fptrgroup("rtos_test_spi_slave_xfer_done_fptr_grp"))) @@ -37,6 +37,7 @@ int spi_device_tests(rtos_spi_master_t *spi_master_ctx, rtos_spi_master_device_t /* Local Tests */ void register_single_transaction_test(spi_test_ctx_t *test_ctx); void register_multiple_transaction_test(spi_test_ctx_t *test_ctx); +void register_slave_default_buffer_test(spi_test_ctx_t *test_ctx); /* RPC Tests */ void register_rpc_single_transaction_test(spi_test_ctx_t *test_ctx); diff --git a/tools/ci/build_host_apps.sh b/tools/ci/build_host_apps.sh index faa66dd10..f9c861bfb 100755 --- a/tools/ci/build_host_apps.sh +++ b/tools/ci/build_host_apps.sh @@ -9,6 +9,14 @@ source ${XCORE_SDK_ROOT}/tools/ci/helper_functions.sh DIST_DIR=${XCORE_SDK_ROOT}/dist_host mkdir -p ${DIST_DIR} +# row format is: "target copy_path" +applications=( + "example_freertos_device_control_host examples/freertos/device_control/host" + "fatfs_mkimage modules/rtos/modules/sw_services/fatfs/host" + "xscope_host_endpoint modules/xscope_fileio/xscope_fileio/host" + "xscope2psf examples/freertos/tracealyzer/host" +) + # perform builds path="${XCORE_SDK_ROOT}" echo '******************************************************' @@ -17,14 +25,12 @@ echo '******************************************************' (cd ${path}; rm -rf build_host) (cd ${path}; mkdir -p build_host) -(cd ${path}/build_host; log_errors cmake ../ ; log_errors make -j) - -# copy example_freertos_device_control_host to dist -name=device_control/host -make_target=example_freertos_device_control_host -(cd ${path}/build_host; cp examples/freertos/${name}/${make_target} ${DIST_DIR}) +(cd ${path}/build_host; log_errors cmake ../) -# copy fatfs_mkimage to dist -name=fatfs/host -make_target=fatfs_mkimage -(cd ${path}/build_host; cp modules/rtos/modules/sw_services/${name}/${make_target} ${DIST_DIR}) +for ((i = 0; i < ${#applications[@]}; i += 1)); do + read -ra FIELDS <<< ${applications[i]} + target="${FIELDS[0]}" + copy_path="${FIELDS[1]}" + (cd ${path}/build_host; log_errors make ${target} -j) + (cd ${path}/build_host; cp ${copy_path}/${target} ${DIST_DIR}) +done diff --git a/tools/ci/build_metal_examples.sh b/tools/ci/build_metal_examples.sh index 56f1ba3ed..267fa6251 100755 --- a/tools/ci/build_metal_examples.sh +++ b/tools/ci/build_metal_examples.sh @@ -27,6 +27,5 @@ for ((i = 0; i < ${#applications[@]}; i += 1)); do (cd ${path}; rm -rf build_${board}) (cd ${path}; mkdir -p build_${board}) - (cd ${path}/build_${board}; log_errors cmake ../ -DCMAKE_TOOLCHAIN_FILE=${toolchain_file} -DBOARD=${board}; log_errors make ${make_target} -j) - (cd ${path}/build_${board}; cp ${make_target}.xe ${DIST_DIR}) + (cd ${path}/build_${board}; log_errors cmake ../ -DCMAKE_TOOLCHAIN_FILE=${toolchain_file} -DBOARD=${board}; log_errors make install_${make_target} -j) done diff --git a/tools/ci/build_rtos_aiot_examples.sh b/tools/ci/build_rtos_aiot_examples.sh index f9e1776f7..7ca434304 100755 --- a/tools/ci/build_rtos_aiot_examples.sh +++ b/tools/ci/build_rtos_aiot_examples.sh @@ -36,8 +36,7 @@ for ((i = 0; i < ${#applications[@]}; i += 1)); do (cd ${path}; rm -rf build_${board}) (cd ${path}; mkdir -p build_${board}) - (cd ${path}/build_${board}; log_errors cmake ../ -DCMAKE_TOOLCHAIN_FILE=${toolchain_file} -DBOARD=${board}; log_errors make ${app_target} -j) - (cd ${path}/build_${board}; cp ${app_target}.xe ${DIST_DIR}) + (cd ${path}/build_${board}; log_errors cmake ../ -DCMAKE_TOOLCHAIN_FILE=${toolchain_file} -DBOARD=${board}; log_errors make install_${app_target} -j) if [ "$run_fs_target" = "Yes" ]; then echo '======================================================' echo '= Making filesystem for' ${app_target} diff --git a/tools/ci/build_rtos_core_examples.sh b/tools/ci/build_rtos_core_examples.sh index 8a733e7f9..06e776ffb 100755 --- a/tools/ci/build_rtos_core_examples.sh +++ b/tools/ci/build_rtos_core_examples.sh @@ -16,44 +16,63 @@ if [ -d "${DIST_HOST_DIR}" ]; then find ${DIST_HOST_DIR} -type f -exec chmod a+x {} + fi -# row format is: "name app_target run_fs_target run_swmem_target board toolchain" +# row format is: "target min_tools_version run_fs_target run_swmem_target run_upgrade_img_target board toolchain" applications=( - "example_freertos_device_control No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" - "example_freertos_dispatcher No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" - "example_freertos_explorer_board Yes No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" - "example_freertos_getting_started No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" - "example_freertos_l2_cache No Yes XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_device_control 15.1.0 No No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_dfu_v1 15.1.3 No No Yes XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_dfu_v2 15.1.3 No No Yes XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_dfu_v1 15.2.0 No No Yes XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_dfu_v2 15.2.0 No No Yes XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_explorer_board 15.1.0 Yes No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_getting_started 15.1.0 No No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_l2_cache 15.1.0 No Yes No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_tracealyzer 15.1.0 No No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_xlink_0 15.2.0 No No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_xlink_1 15.2.0 No No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" + "example_freertos_xscope_fileio 15.1.0 No No No XCORE-AI-EXPLORER xmos_cmake_toolchain/xs3a.cmake" ) # perform builds for ((i = 0; i < ${#applications[@]}; i += 1)); do read -ra FIELDS <<< ${applications[i]} app_target="${FIELDS[0]}" - run_fs_target="${FIELDS[1]}" - run_swmem_target="${FIELDS[2]}" - board="${FIELDS[3]}" - toolchain_file="${XCORE_SDK_ROOT}/${FIELDS[4]}" + min_tools_version="${FIELDS[1]}" + run_fs_target="${FIELDS[2]}" + run_swmem_target="${FIELDS[3]}" + run_upgrade_img_target="${FIELDS[4]}" + board="${FIELDS[5]}" + toolchain_file="${XCORE_SDK_ROOT}/${FIELDS[6]}" path="${XCORE_SDK_ROOT}" - echo '******************************************************' - echo '* Building' ${app_target} 'for' ${board} - echo '******************************************************' - (cd ${path}; rm -rf build_${board}) - (cd ${path}; mkdir -p build_${board}) - (cd ${path}/build_${board}; log_errors cmake ../ -DCMAKE_TOOLCHAIN_FILE=${toolchain_file} -DBOARD=${board}; log_errors make ${app_target} -j) - (cd ${path}/build_${board}; cp ${app_target}.xe ${DIST_DIR}) - if [ "$run_fs_target" = "Yes" ]; then - echo '======================================================' - echo '= Making filesystem for' ${app_target} - echo '======================================================' - (cd ${path}/build_${board}; log_errors make make_fs_${app_target} -j) - (cd ${path}/build_${board}; cp ${app_target}_fat.fs ${DIST_DIR}) - fi - if [ "$run_swmem_target" = "Yes" ]; then - echo '======================================================' - echo '= Making swmem for' ${app_target} - echo '======================================================' - (cd ${path}/build_${board}; log_errors make make_swmem_${app_target} -j) - (cd ${path}/build_${board}; cp ${app_target}.swmem ${DIST_DIR}) + if check_tools_version ${min_tools_version} + then + echo '******************************************************' + echo '* Building' ${app_target} 'for' ${board} + echo '******************************************************' + + (cd ${path}; rm -rf build_${board}) + (cd ${path}; mkdir -p build_${board}) + (cd ${path}/build_${board}; log_errors cmake ../ -DCMAKE_TOOLCHAIN_FILE=${toolchain_file} -DBOARD=${board}; log_errors make install_${app_target} -j) + if [ "$run_fs_target" = "Yes" ]; then + echo '======================================================' + echo '= Making filesystem for' ${app_target} + echo '======================================================' + (cd ${path}/build_${board}; log_errors make make_fs_${app_target} -j) + (cd ${path}/build_${board}; cp ${app_target}_fat.fs ${DIST_DIR}) + fi + if [ "$run_swmem_target" = "Yes" ]; then + echo '======================================================' + echo '= Making swmem for' ${app_target} + echo '======================================================' + (cd ${path}/build_${board}; log_errors make make_swmem_${app_target} -j) + (cd ${path}/build_${board}; cp ${app_target}.swmem ${DIST_DIR}) + fi + if [ "$run_upgrade_img_target" = "Yes" ]; then + echo '======================================================' + echo '= Making upgrade image for' ${app_target} + echo '======================================================' + (cd ${path}/build_${board}; log_errors make create_upgrade_img_${app_target} -j) + (cd ${path}/build_${board}; cp ${app_target}_upgrade.bin ${DIST_DIR}) + fi fi done diff --git a/tools/ci/helper_functions.sh b/tools/ci/helper_functions.sh index 436a02b3e..73dc4fc3e 100644 --- a/tools/ci/helper_functions.sh +++ b/tools/ci/helper_functions.sh @@ -22,4 +22,38 @@ function get_timeout { elif [[ "$uname" == 'Darwin' ]]; then echo "gtimeout" fi -} \ No newline at end of file +} + +function check_tools_version { + # Get required version fields + IFS='.' read -ra FIELDS <<< "$@" + MIN_VERSION_MAJOR=${FIELDS[0]} + MIN_VERSION_MINOR=${FIELDS[1]} + MIN_VERSION_PATCH=${FIELDS[2]} + # Run xcc --version + xcc_version_output_string=`cat "$XMOS_TOOL_PATH"/doc/version.txt` + # Find the semantic version substring + prefix=${xcc_version_output_string%%" "*} + space_position=${#prefix} + xcc_semver_substring=`echo $xcc_version_output_string | cut -c1-$space_position` + # Split semver substring into fields + IFS='.' read -ra FIELDS <<< "$xcc_semver_substring" + XTC_VERSION_MAJOR=${FIELDS[0]} + XTC_VERSION_MINOR=${FIELDS[1]} + XTC_VERSION_PATCH=${FIELDS[2]} + # Check version + if [ "$XTC_VERSION_MAJOR" -lt "$MIN_VERSION_MAJOR" ] + then + return 1 + else + if [ "$XTC_VERSION_MINOR" -lt "$MIN_VERSION_MINOR" ] + then + return 1 + else + if [ "$XTC_VERSION_PATCH" -lt "$MIN_VERSION_PATCH" ] + then + return 1 + fi + fi + fi +} diff --git a/tools/install/contribute.txt b/tools/install/contribute.txt index 9a718f68a..bea4d5c72 100644 --- a/tools/install/contribute.txt +++ b/tools/install/contribute.txt @@ -3,5 +3,3 @@ nbval pytest pytest-forked pytest-xdist --e git+https://git@github.com/ACascarino/test_support.git@06373a0da65f80fcda3e2b754ceb34a4a8b79af6#egg=test_support -