Voice Activity Detection secure partition added
Change-Id: Ic1b6b3fbde57a8b52545689c312deb5c6e264c02
Co-authored-by: Gabor Toth <gabor.toth@arm.com>
Signed-off-by: Mark Horvath <mark.horvath@arm.com>
diff --git a/partitions/partitions_readme.rst b/partitions/partitions_readme.rst
index d0de660..a3b3092 100755
--- a/partitions/partitions_readme.rst
+++ b/partitions/partitions_readme.rst
@@ -59,6 +59,21 @@
-----------
- David Vincze `<David.Vincze@arm.com>`_
+vad_an552_sp
+============
+
+Description
+-----------
+Secure partition for the AN552 FPGA image. It implements voice activity
+detection on the microphone input of the MPS3 board, and if voice detected
+(which can be any noise) a short sample (~100 ms) is recorded. Then it can be
+calculated that which frequency component has the highest energy in the
+recorded sample.
+
+Maintainers
+-----------
+- Gabor Toth `<gabor.toth@arm.com> <gabor.toth@arm.com>`_
+- Mark Horvath `<mark.horvath@arm.com> <mark.horvath@arm.com>`_
---------------------------
diff --git a/partitions/vad_an552_sp/CMakeLists.txt b/partitions/vad_an552_sp/CMakeLists.txt
new file mode 100644
index 0000000..efbf00a
--- /dev/null
+++ b/partitions/vad_an552_sp/CMakeLists.txt
@@ -0,0 +1,106 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 3.15)
+cmake_policy(SET CMP0079 NEW)
+
+# Voice activity algorithm is fetched from external repository
+set(ARM_ENDPOINTAI_SRC_PATH "DOWNLOAD" CACHE PATH "Path to Arm's EndpointAI repository (or DOWNLOAD to fetch automatically")
+add_subdirectory(ext/arm-endpoint-ai)
+
+# CMSIS 5 repository
+set(CMSIS_5_SRC_PATH "DOWNLOAD" CACHE PATH "Path to CMSIS_5 repository (or DOWNLOAD to fetch automatically")
+add_subdirectory(ext/CMSIS)
+
+add_library(tfm_app_rot_partition_vad_an552 STATIC)
+
+target_sources(tfm_app_rot_partition_vad_an552
+ PRIVATE
+ Libraries/audio_codec_mps3.c
+ Libraries/systimer_armv8-m_timeout.c
+ native_drivers/i2c_sbcon_drv.c
+ native_drivers/audio_i2s_mps3_drv.c
+ ${CMAKE_SOURCE_DIR}/platform/ext/target/arm/mps3/an552/native_drivers/systimer_armv8-m_drv.c
+ vad_an552_device_definition.c
+ vad_an552_sp_main.c
+
+ ${ARM_ENDPOINTAI_SRC_PATH}/Kernels/tinyVAD/tinyVAD.c
+
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/StatisticsFunctions/arm_max_q15.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/ComplexMathFunctions/arm_cmplx_mag_q15.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/FastMathFunctions/arm_sqrt_q15.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/TransformFunctions/arm_rfft_q15.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/TransformFunctions/arm_rfft_init_q15.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/TransformFunctions/arm_cfft_q15.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/BasicMathFunctions/arm_shift_q15.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/CommonTables/arm_common_tables.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/CommonTables/arm_const_structs.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/TransformFunctions/arm_cfft_radix4_q15.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/TransformFunctions/arm_bitreversal2.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/TransformFunctions/arm_bitreversal.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/TransformFunctions/arm_cfft_init_q15.c
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Source/CommonTables/arm_mve_tables.c
+)
+
+target_include_directories(tfm_app_rot_partition_vad_an552
+ PRIVATE
+ .
+ Libraries
+ native_drivers
+ ns_interface
+ ${CMAKE_BINARY_DIR}/generated
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/Include
+ ${CMSIS_5_SRC_PATH}/CMSIS/DSP/PrivateInclude
+)
+
+target_compile_definitions(tfm_app_rot_partition_vad_an552
+ INTERFACE
+ CONFIG_TFM_BUILDING_SPE=1
+ ARM_ALL_FFT_TABLES
+)
+
+target_compile_options(tfm_app_rot_partition_vad_an552
+ PRIVATE
+ -flax-vector-conversions
+)
+
+target_include_directories(tfm_partitions
+ INTERFACE
+ .
+ ${CMAKE_BINARY_DIR}/generated
+)
+
+# IRQ handler should be part of SPM, the actual handling of the IRQ is done
+# in the partition
+target_sources(tfm_spm
+ PRIVATE
+ i2s_spm_irq.c
+)
+
+# The generated sources
+target_sources(tfm_app_rot_partition_vad_an552
+ PRIVATE
+ ${CMAKE_BINARY_DIR}/generated/auto_generated/intermedia_vad_an552_sp.c
+)
+target_sources(tfm_partitions
+ INTERFACE
+ ${CMAKE_BINARY_DIR}/generated/auto_generated/load_info_vad_an552_sp.c
+)
+
+target_link_libraries(tfm_app_rot_partition_vad_an552
+ PRIVATE
+ psa_interface
+ platform_s
+ tfm_sprt
+)
+
+############################ Partition Defs ####################################
+
+target_link_libraries(tfm_partitions
+ INTERFACE
+ tfm_app_rot_partition_vad_an552
+)
diff --git a/partitions/vad_an552_sp/Libraries/audio_codec_mps3.c b/partitions/vad_an552_sp/Libraries/audio_codec_mps3.c
new file mode 100644
index 0000000..bfccd05
--- /dev/null
+++ b/partitions/vad_an552_sp/Libraries/audio_codec_mps3.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "audio_codec_mps3.h"
+#include "i2c_sbcon_drv.h"
+#include "audio_i2s_mps3_drv.h"
+#include "timeout.h"
+
+#define CHIP_ADDR_WRITE 0x96
+#define CHIP_ADDR_READ 0x97
+
+/**
+ * \brief CS42L52 Audio Codec registers
+ */
+#define AUDIO_CODEC_MPS3_CHIP_ID 0x01 /*!< Chip ID and Revision Register */
+#define AUDIO_CODEC_MPS3_PWR_CTRL1 0x02 /*!< Power Control 1 */
+#define AUDIO_CODEC_MPS3_PWR_CTRL2 0x03 /*!< Power Control 2 */
+#define AUDIO_CODEC_MPS3_PWR_CTRL3 0x04 /*!< Power Control 3 */
+#define AUDIO_CODEC_MPS3_CLK_CTRL 0x05 /*!< Clocking Control */
+#define AUDIO_CODEC_MPS3_INT_CTRL1 0x06 /*!< Interface Control 1 */
+#define AUDIO_CODEC_MPS3_INT_CTRL2 0x07 /*!< Interface Control 2 */
+#define AUDIO_CODEC_MPS3_INPUT_A 0x08 /*!< Input x Select: ADCA and PGAA */
+#define AUDIO_CODEC_MPS3_INPUT_B 0x09 /*!< Input x Select: ADCB and PGAB */
+#define AUDIO_CODEC_MPS3_AMP_A 0x10 /*!< MICx Amp Control:MIC A */
+#define AUDIO_CODEC_MPS3_AMP_B 0x11 /*!< MICx Amp Control:MIC B */
+#define AUDIO_CODEC_MPS3_MISC_CTRL 0x0E /*!< Miscellaneous Controls */
+
+static void audio_codec_mps3_write(struct i2c_sbcon_dev_t *i2c_sbcon_dev,
+ uint8_t map_byte, uint8_t data)
+{
+ uint32_t i;
+ uint8_t to_write[2];
+
+ to_write[0] = map_byte;
+ to_write[1] = data;
+ i2c_sbcon_master_transmit(
+ i2c_sbcon_dev, CHIP_ADDR_WRITE, to_write, 2, 0, &i);
+}
+
+static uint8_t audio_codec_mps3_read(struct i2c_sbcon_dev_t *i2c_sbcon_dev,
+ uint8_t map_byte)
+{
+ uint32_t i;
+ uint8_t data;
+
+ i2c_sbcon_master_transmit(
+ i2c_sbcon_dev, CHIP_ADDR_WRITE, &map_byte, 1, 0, &i);
+ i2c_sbcon_master_receive(i2c_sbcon_dev, CHIP_ADDR_READ, &data, 1, 0, &i);
+
+ return data;
+}
+
+enum audio_codec_mps3_error_t audio_codec_mps3_init(
+ struct i2c_sbcon_dev_t *i2c_sbcon_dev,
+ struct audio_i2s_mps3_dev_t *audio_i2s_mps3_dev)
+{
+ uint8_t reg_32;
+
+ i2c_sbcon_init(i2c_sbcon_dev, WAIT_US_FREQ_HZ);
+ audio_i2s_mps3_set_codec_reset(audio_i2s_mps3_dev);
+ wait_ms(1);
+
+ audio_i2s_mps3_clear_codec_reset(audio_i2s_mps3_dev);
+ wait_ms(1);
+
+ /* Initialization with values given in the Reference Manual */
+ audio_codec_mps3_write(i2c_sbcon_dev, 0x00, 0x99);
+ audio_codec_mps3_write(i2c_sbcon_dev, 0x3E, 0xBA);
+ audio_codec_mps3_write(i2c_sbcon_dev, 0x47, 0x80);
+ reg_32 = audio_codec_mps3_read(i2c_sbcon_dev, 0x32);
+ audio_codec_mps3_write(i2c_sbcon_dev, 0x32, reg_32 | 0x80);
+ audio_codec_mps3_write(i2c_sbcon_dev, 0x32, reg_32 & 0x7F);
+ audio_codec_mps3_write(i2c_sbcon_dev, 0x00, 0x00);
+ wait_ms(1);
+
+ /* Single-speed mode */
+ audio_codec_mps3_write(i2c_sbcon_dev, AUDIO_CODEC_MPS3_CLK_CTRL, 0x20);
+ /* ADC charge pump and PGA & ADC channels powered up */
+ audio_codec_mps3_write(i2c_sbcon_dev, AUDIO_CODEC_MPS3_PWR_CTRL1, 0x00);
+ /* MIC powered up */
+ audio_codec_mps3_write(i2c_sbcon_dev, AUDIO_CODEC_MPS3_PWR_CTRL2, 0x00);
+ /* Headphone and Speaker channel always on */
+ audio_codec_mps3_write(i2c_sbcon_dev, AUDIO_CODEC_MPS3_PWR_CTRL3, 0xAA);
+ /* Select analog input for PGA AIN4A and AIN4B */
+ audio_codec_mps3_write(i2c_sbcon_dev, AUDIO_CODEC_MPS3_INPUT_A, 0x90);
+ audio_codec_mps3_write(i2c_sbcon_dev, AUDIO_CODEC_MPS3_INPUT_B, 0x90);
+ /* Select MIC inputs and sets microphone pre-amplifier 32 dB */
+ audio_codec_mps3_write(i2c_sbcon_dev, AUDIO_CODEC_MPS3_AMP_A, 0x5F);
+ audio_codec_mps3_write(i2c_sbcon_dev, AUDIO_CODEC_MPS3_AMP_B, 0x5F);
+ /* De-emphasis filter enabled */
+ audio_codec_mps3_write(i2c_sbcon_dev, AUDIO_CODEC_MPS3_MISC_CTRL, 0x04);
+ wait_ms(1);
+
+ return AUDIO_CODEC_MPS3_ERR_NONE;
+}
diff --git a/partitions/vad_an552_sp/Libraries/audio_codec_mps3.h b/partitions/vad_an552_sp/Libraries/audio_codec_mps3.h
new file mode 100644
index 0000000..f8112eb
--- /dev/null
+++ b/partitions/vad_an552_sp/Libraries/audio_codec_mps3.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/**
+ * \file audio_codec_mps3.h
+ *
+ * \brief CS42L52 Audio Codec configuration.
+ * The control port operates using an I2C interface.
+ */
+
+#ifndef __AUDIO_CODEC_MPS3_H__
+#define __AUDIO_CODEC_MPS3_H__
+
+#include <stdint.h>
+#include "i2c_sbcon_drv.h"
+#include "audio_i2s_mps3_drv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief CS42L52 Audio Codec error enumeration types
+ */
+enum audio_codec_mps3_error_t {
+ AUDIO_CODEC_MPS3_ERR_NONE = 0, /*!< No error */
+};
+
+/**
+ * \brief Initializes Audio Codec
+ *
+ * \param[in] i2c_sbcon_dev I2C device struct \ref i2c_sbcon_dev
+ * \param[in] audio_i2s_mps3_dev I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \return Returns error code as specified in \ref audio_codec_mps3_error_t
+ */
+enum audio_codec_mps3_error_t audio_codec_mps3_init(
+ struct i2c_sbcon_dev_t *i2c_sbcon_dev,
+ struct audio_i2s_mps3_dev_t *audio_i2s_mps3_dev);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __AUDIO_CODEC_MPS3_H__ */
diff --git a/partitions/vad_an552_sp/Libraries/systimer_armv8-m_timeout.c b/partitions/vad_an552_sp/Libraries/systimer_armv8-m_timeout.c
new file mode 100644
index 0000000..4913e27
--- /dev/null
+++ b/partitions/vad_an552_sp/Libraries/systimer_armv8-m_timeout.c
@@ -0,0 +1,108 @@
+/*
+* Copyright (c) 2019-2022 Arm Limited
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "timeout.h"
+#include "systimer_armv8-m_drv.h"
+#include "vad_an552_device_definition.h"
+
+#define MS_TO_TICK(ms) ((ms) * (SYSTIMER3_ARMV8M_DEFAULT_FREQ_HZ / 1000))
+#define US_TO_TICK(us) ((us) * (SYSTIMER3_ARMV8M_DEFAULT_FREQ_HZ) / 1000000)
+/* Systimer is configured over the 32-bit down-counting Timer view, so maximum
+ * delay is defined by its bit width. */
+#define MAX_DELAY_MS (UINT32_MAX / \
+ (SYSTIMER3_ARMV8M_DEFAULT_FREQ_HZ / 1000))
+#define MAX_DELAY_US (UINT32_MAX / \
+ (SYSTIMER3_ARMV8M_DEFAULT_FREQ_HZ / 1000000))
+static uint32_t delay_in_tick;
+
+bool timeout_init(struct timeout_t *timeout, uint32_t delay)
+{
+ struct systimer_armv8_m_dev_t *dev;
+
+ if (!timeout || delay > MAX_DELAY_MS) {
+ return false;
+ }
+
+ if (timeout->is_initialized) {
+ return false;
+ }
+
+ dev = &SYSTIMER3_ARMV8_M_DEV_S;
+ systimer_armv8_m_init(dev);
+
+ delay_in_tick = MS_TO_TICK(delay);
+ systimer_armv8_m_set_timer_value(dev, delay_in_tick);
+
+ timeout->dev_ptr = (void *)dev;
+ timeout->is_initialized = true;
+
+ return true;
+}
+
+bool timeout_init_us(struct timeout_t *timeout, uint32_t delay)
+{
+ struct systimer_armv8_m_dev_t *dev;
+
+ if (!timeout || delay > MAX_DELAY_US) {
+ return false;
+ }
+
+ if (timeout->is_initialized) {
+ return false;
+ }
+
+ dev = &SYSTIMER3_ARMV8_M_DEV_S;
+ systimer_armv8_m_init(dev);
+
+ delay_in_tick = US_TO_TICK(delay);
+ systimer_armv8_m_set_timer_value(dev, delay_in_tick);
+
+ timeout->dev_ptr = (void *)dev;
+ timeout->is_initialized = true;
+
+ return true;
+}
+
+bool timeout_delay_is_elapsed(struct timeout_t *timeout)
+{
+ struct systimer_armv8_m_dev_t* dev;
+
+ if (!timeout || !timeout->is_initialized) {
+ return false;
+ }
+
+ dev = (struct systimer_armv8_m_dev_t*)timeout->dev_ptr;
+ if (systimer_armv8_m_is_interrupt_asserted(dev)) {
+ systimer_armv8_m_set_timer_value(dev, delay_in_tick);
+ return true;
+ }
+
+ return false;
+}
+
+void wait_us(uint32_t usec)
+{
+ static struct timeout_t timeout = {false, false};
+ timeout_init_us(&timeout, usec);
+ while (!timeout_delay_is_elapsed(&timeout));
+}
+
+void wait_ms(uint32_t ms)
+{
+ static struct timeout_t timeout = {false, false};
+ timeout_init(&timeout, ms);
+ while (!timeout_delay_is_elapsed(&timeout));
+}
diff --git a/partitions/vad_an552_sp/Libraries/timeout.h b/partitions/vad_an552_sp/Libraries/timeout.h
new file mode 100644
index 0000000..d0998b1
--- /dev/null
+++ b/partitions/vad_an552_sp/Libraries/timeout.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017-2022 Arm Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIMEOUT_H__
+#define __TIMEOUT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "vad_an552_device_definition.h"
+
+#define WAIT_US_FREQ_HZ SYSTIMER3_ARMV8M_DEFAULT_FREQ_HZ
+
+/* Structure to maintain elapsed time */
+struct timeout_t {
+ void *dev_ptr;
+ bool is_initialized;
+};
+
+/**
+ * \brief Initializes timeout structure
+ *
+ * \param[in] timeout Pointer to the timeout structure
+ * \param[in] delay Delay in ms to check timeout against
+ *
+ * \return Returns true if the delay value was set,
+ * false otherwise
+ */
+bool timeout_init(struct timeout_t *timeout, uint32_t delay);
+
+/**
+ * \brief Initializes timeout structure
+ *
+ * \param[in] timeout Pointer to the timeout structure
+ * \param[in] delay Delay in us to check timeout against
+ *
+ * \return Returns true if the delay value was set,
+ * false otherwise
+ */
+bool timeout_init_us(struct timeout_t *timeout, uint32_t delay);
+
+/**
+ * \brief Checks if the given time has passed or not
+ *
+ * \param[in] timer Pointer to the timer structure
+ *
+ * \details This function compares the timestamp stored in the timeout structure
+ * and the current time. If the difference is more than the given delay,
+ * the current time is stored and will be used for the next comparison
+ *
+ * \return 1 if the given time has passed, 0 if not
+ */
+bool timeout_delay_is_elapsed(struct timeout_t *timeout);
+
+/**
+ * \brief Uninitializes timout structure and stops timer operation.
+ *
+ * \param[in] timeout Pointer to the timeout structure
+ */
+void timeout_uninit(struct timeout_t *timeout);
+
+/**
+ * \brief Waits the specified time in milliseconds.
+ *
+ * \param[in] ms Time to wait in milliseconds
+ */
+void wait_ms(uint32_t ms);
+
+/**
+ * \brief Waits the specified time in microseconds.
+ *
+ * \param[in] us Time to wait in microseconds
+ */
+void wait_us(uint32_t us);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIMEOUT_H__ */
diff --git a/partitions/vad_an552_sp/ext/CMSIS/CMakeLists.txt b/partitions/vad_an552_sp/ext/CMSIS/CMakeLists.txt
new file mode 100644
index 0000000..d54b898
--- /dev/null
+++ b/partitions/vad_an552_sp/ext/CMSIS/CMakeLists.txt
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+include(FetchContent)
+set(FETCHCONTENT_QUIET FALSE)
+
+# Needed to specfy submodule list
+if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
+ cmake_policy(SET CMP0097 NEW)
+endif()
+
+if ("${CMSIS_5_SRC_PATH}" STREQUAL "DOWNLOAD")
+ find_package(Git)
+
+ FetchContent_Declare(cmsis_5
+ GIT_REPOSITORY https://github.com/ARM-software/CMSIS_5.git
+ GIT_TAG 5.8.0
+ )
+ FetchContent_GetProperties(cmsis_5)
+ if (NOT cmsis_5)
+ FetchContent_Populate(cmsis_5)
+ set(CMSIS_5_SRC_PATH ${cmsis_5_SOURCE_DIR} CACHE PATH "Path to CMSIS_5 repository (or DOWNLOAD to fetch automatically" FORCE)
+ endif ()
+endif ()
diff --git a/partitions/vad_an552_sp/ext/arm-endpoint-ai/CMakeLists.txt b/partitions/vad_an552_sp/ext/arm-endpoint-ai/CMakeLists.txt
new file mode 100644
index 0000000..1983e5f
--- /dev/null
+++ b/partitions/vad_an552_sp/ext/arm-endpoint-ai/CMakeLists.txt
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+include(FetchContent)
+set(FETCHCONTENT_QUIET FALSE)
+
+# Needed to specfy submodule list
+if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0")
+ cmake_policy(SET CMP0097 NEW)
+endif()
+
+if ("${ARM_ENDPOINTAI_SRC_PATH}" STREQUAL "DOWNLOAD")
+ find_package(Git)
+
+ FetchContent_Declare(arm_endpoint_ai
+ GIT_REPOSITORY https://github.com/ARM-software/EndpointAI.git
+ GIT_TAG 80c5b64888ba9f5d26defb4db0ef178786ff65b9
+ )
+ FetchContent_GetProperties(arm_endpoint_ai)
+ if (NOT arm_endpoint_ai)
+ FetchContent_Populate(arm_endpoint_ai)
+ set(ARM_ENDPOINTAI_SRC_PATH ${arm_endpoint_ai_SOURCE_DIR} CACHE PATH "Path to Arm's EndpointAI repository (or DOWNLOAD to fetch automatically" FORCE)
+ endif ()
+endif ()
diff --git a/partitions/vad_an552_sp/extra_manifest_list.yaml b/partitions/vad_an552_sp/extra_manifest_list.yaml
new file mode 100644
index 0000000..a1bde45
--- /dev/null
+++ b/partitions/vad_an552_sp/extra_manifest_list.yaml
@@ -0,0 +1,27 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2018-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+ "description": "Extra manifest list for VAD AN552 example",
+ "type": "manifest_list",
+ "version_major": 0,
+ "version_minor": 1,
+ "manifest_list": [
+ {
+ "description": "VAD AN552 Example Partition",
+ "manifest": "vad_an552_sp.yaml",
+ "version_major": 0,
+ "version_minor": 1,
+ "pid": 274,
+ "linker_pattern": {
+ "library_list": [
+ "*vad_an552.*"
+ ]
+ }
+ }
+ ]
+}
diff --git a/partitions/vad_an552_sp/i2s_spm_irq.c b/partitions/vad_an552_sp/i2s_spm_irq.c
new file mode 100644
index 0000000..bf072f8
--- /dev/null
+++ b/partitions/vad_an552_sp/i2s_spm_irq.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+
+#include "cmsis.h"
+#include "ffm/interrupt.h"
+#include "load/interrupt_defs.h"
+#include "tfm_peripherals_def.h"
+
+/* Structure for IRQ handling by SPM */
+static struct irq_t i2s_irq = {0};
+
+void I2S_Handler(void)
+{
+ spm_handle_interrupt(i2s_irq.p_pt, i2s_irq.p_ildi);
+}
+
+enum tfm_hal_status_t i2s_irqn_init(void *p_pt,
+ struct irq_load_info_t *p_ildi)
+{
+ i2s_irq.p_ildi = p_ildi;
+ i2s_irq.p_pt = p_pt;
+
+ NVIC_SetPriority(I2S_IRQn, DEFAULT_IRQ_PRIORITY);
+ NVIC_ClearTargetState(I2S_IRQn);
+ NVIC_DisableIRQ(I2S_IRQn);
+
+ return TFM_HAL_SUCCESS;
+}
diff --git a/partitions/vad_an552_sp/native_drivers/audio_i2s_mps3_drv.c b/partitions/vad_an552_sp/native_drivers/audio_i2s_mps3_drv.c
new file mode 100644
index 0000000..803b820
--- /dev/null
+++ b/partitions/vad_an552_sp/native_drivers/audio_i2s_mps3_drv.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "audio_i2s_mps3_drv.h"
+
+/**
+ * \brief Audio I2S register map structure
+ */
+struct audio_i2s_mps3_reg_map_t{
+ /* Offset: 0x000 (R/W) Control Register */
+ volatile uint32_t control;
+ /* Offset: 0x004 (R/W) Status Register */
+ volatile uint32_t status;
+ /* Offset: 0x008 (R/W) Error Register */
+ volatile uint32_t error;
+ /* Offset: 0x00C (R/W) Clock Divide Ratio Register */
+ volatile uint32_t divide;
+ /* Offset: 0x010 (W) Transmit Buffer FIFO Data Register */
+ volatile uint32_t txbuf;
+ /* Offset: 0x014 (R) Receive Buffer FIFO Data Register */
+ volatile uint32_t rxbuf;
+ /*!< Offset: 0x018-0x2FF Reserved */
+ volatile const uint32_t reserved[14];
+ /* Offset: 0x300 (R/W) Integration Test Control Register */
+ volatile uint32_t itcr;
+ /* Offset: 0x304 (R/W) Integration Test Input Register */
+ volatile uint32_t itip1;
+ /* Offset: 0x308 (R/W) Integration Test Output Register */
+ volatile uint32_t itop1;
+};
+
+/**
+ * \brief Audio I2S Control Register bit fields
+ */
+#define AUDIO_I2S_MPS3_CONTROL_TX_EN_OFF 0u
+ /*!< Audio I2S Control Register Tx Enable bit field offset */
+#define AUDIO_I2S_MPS3_CONTROL_TX_INTREN_OFF 1u
+ /*!< Audio I2S Control Register Tx Interrupt Enable bit field offset */
+#define AUDIO_I2S_MPS3_CONTROL_RX_EN_OFF 2u
+ /*!< Audio I2S Control Register Rx Enable bit field offset */
+#define AUDIO_I2S_MPS3_CONTROL_RX_INTREN_OFF 3u
+ /*!< Audio I2S Control Register Rx Interrupt Enable bit field offset */
+#define AUDIO_I2S_MPS3_CONTROL_TX_BUFF_IRQ_WATER_LVL_OFF 8u
+ /*!< Audio I2S Control Register Tx Buffer Interrupt Water Level Offset */
+#define AUDIO_I2S_MPS3_CONTROL_RX_BUFF_IRQ_WATER_LVL_OFF 12u
+ /*!< Audio I2S Control Register Rx Buffer Interrupt Water Level Offset */
+#define AUDIO_I2S_MPS3_CONTROL_FIFO_RESET_OFF 16u
+ /*!< Audio I2S Control Register FIFO Reset bit field offset */
+#define AUDIO_I2S_MPS3_CONTROL_CODEC_RESET_OFF 17u
+ /*!< Audio I2S Control Register Audio Codec Reset bit field offset */
+
+/**
+ * \brief Audio I2S Status Register bit fields
+ */
+#define AUDIO_I2S_MPS3_STATUS_TXBUF_EMPTY_OFF 2u
+ /*!< Audio I2S Status Register Tx Buffer Empty bit field offset */
+#define AUDIO_I2S_MPS3_STATUS_TXBUF_FULL_OFF 3u
+ /*!< Audio I2S Status Register Tx Buffer Full bit field offset */
+#define AUDIO_I2S_MPS3_STATUS_RXBUF_EMPTY_OFF 4u
+ /*!< Audio I2S Status Register Tx Buffer Empty bit field offset */
+#define AUDIO_I2S_MPS3_STATUS_RXBUF_FULL_OFF 5u
+ /*!< Audio I2S Status Register Tx Buffer Full bit field offset */
+
+#define LRDIV_MAX_VALUE 0x3FF
+
+void audio_i2s_mps3_set_codec_reset(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s =
+ (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control |= (1 << AUDIO_I2S_MPS3_CONTROL_CODEC_RESET_OFF);
+}
+
+void audio_i2s_mps3_set_fifo_reset(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s =
+ (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control |= (1 << AUDIO_I2S_MPS3_CONTROL_FIFO_RESET_OFF);
+}
+
+void audio_i2s_mps3_clear_codec_reset(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control &= ~(1 << AUDIO_I2S_MPS3_CONTROL_CODEC_RESET_OFF);
+}
+
+void audio_i2s_mps3_clear_fifo_reset(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control &= ~(1 << AUDIO_I2S_MPS3_CONTROL_FIFO_RESET_OFF);
+}
+
+enum audio_i2s_mps3_error_t audio_i2s_mps3_speed_config(struct audio_i2s_mps3_dev_t* dev, uint16_t lrdiv)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+
+ if ( lrdiv > LRDIV_MAX_VALUE ) {
+ return AUDIO_I2S_MPS3_ERR_INVALID_ARG;
+ }
+ p_i2s->divide = lrdiv;
+ return AUDIO_I2S_MPS3_ERR_NONE;
+}
+
+bool audio_i2s_mps3_is_rx_buffer_empty(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ return (bool)((p_i2s->status >> AUDIO_I2S_MPS3_STATUS_RXBUF_EMPTY_OFF) & 0x1);
+}
+
+bool audio_i2s_mps3_is_rx_buffer_full(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ return (bool)((p_i2s->status >> AUDIO_I2S_MPS3_STATUS_RXBUF_FULL_OFF) & 0x1);
+}
+
+bool audio_i2s_mps3_is_tx_buffer_empty(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ return (bool)((p_i2s->status >> AUDIO_I2S_MPS3_STATUS_TXBUF_EMPTY_OFF) & 0x1);
+}
+
+bool audio_i2s_mps3_is_tx_buffer_full(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ return (bool)((p_i2s->status >> AUDIO_I2S_MPS3_STATUS_TXBUF_FULL_OFF) & 0x1);
+}
+
+uint32_t audio_i2s_mps3_get_rxbuf(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ return p_i2s->rxbuf;
+}
+
+void audio_i2s_mps3_set_txbuf(struct audio_i2s_mps3_dev_t* dev, uint16_t left_channel,
+ uint16_t right_channel)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ uint32_t sample = ((uint32_t)left_channel) << 16;
+ sample += right_channel;
+ p_i2s->txbuf = sample;
+}
+
+uint32_t audio_i2s_mps3_get_control(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ return p_i2s->control;
+}
+
+uint32_t audio_i2s_mps3_get_status(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ return p_i2s->status;
+}
+
+uint32_t audio_i2s_mps3_get_error(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ return p_i2s->error;
+}
+
+void audio_i2s_mps3_enable_rxbuf(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control |= (1 << AUDIO_I2S_MPS3_CONTROL_RX_EN_OFF);
+}
+
+void audio_i2s_mps3_enable_rxinterrupt(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control |= (1 << AUDIO_I2S_MPS3_CONTROL_RX_INTREN_OFF);
+}
+
+void audio_i2s_mps3_enable_txbuf(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control |= (1 << AUDIO_I2S_MPS3_CONTROL_TX_EN_OFF);
+}
+
+void audio_i2s_mps3_enable_txinterrupt(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control |= (1 << AUDIO_I2S_MPS3_CONTROL_TX_INTREN_OFF);
+}
+
+void audio_i2s_mps3_disable_rxbuf(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control &= ~(1 << AUDIO_I2S_MPS3_CONTROL_RX_EN_OFF);
+}
+
+void audio_i2s_mps3_disable_rxinterrupt(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control &= ~(1 << AUDIO_I2S_MPS3_CONTROL_RX_INTREN_OFF);
+}
+
+void audio_i2s_mps3_disable_txbuf(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control &= ~(1 << AUDIO_I2S_MPS3_CONTROL_TX_EN_OFF);
+}
+
+void audio_i2s_mps3_disable_txinterrupt(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control &= ~(1 << AUDIO_I2S_MPS3_CONTROL_TX_INTREN_OFF);
+}
+
+struct audio_i2s_mps3_sample_t read_sample(struct audio_i2s_mps3_dev_t* dev)
+{
+ struct audio_i2s_mps3_sample_t sample;
+ uint32_t s = audio_i2s_mps3_get_rxbuf(dev);
+ sample.right_channel = s & 0xFFFF;
+ sample.left_channel = s >> 16;
+ return sample;
+}
+
+void write_sample(struct audio_i2s_mps3_dev_t* dev, struct audio_i2s_mps3_sample_t sample)
+{
+ audio_i2s_mps3_set_txbuf(dev, sample.left_channel, sample.right_channel);
+}
+
+void audio_i2s_mps3_set_tx_buff_water_lvl(struct audio_i2s_mps3_dev_t* dev,
+ uint8_t level){
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control = (p_i2s->control & ~(0x7 << AUDIO_I2S_MPS3_CONTROL_TX_BUFF_IRQ_WATER_LVL_OFF)) |
+ ((level & 0x7) << AUDIO_I2S_MPS3_CONTROL_TX_BUFF_IRQ_WATER_LVL_OFF);
+}
+
+uint8_t audio_i2s_mps3_get_tx_buff_water_lvl(struct audio_i2s_mps3_dev_t* dev){
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+
+ return (uint8_t)((p_i2s->control >> AUDIO_I2S_MPS3_CONTROL_TX_BUFF_IRQ_WATER_LVL_OFF) & 0x7);
+}
+
+void audio_i2s_mps3_set_rx_buff_water_lvl(struct audio_i2s_mps3_dev_t* dev,
+ uint8_t level){
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+ p_i2s->control = (p_i2s->control & ~(0x7 << AUDIO_I2S_MPS3_CONTROL_RX_BUFF_IRQ_WATER_LVL_OFF)) |
+ ((level & 0x7) << AUDIO_I2S_MPS3_CONTROL_RX_BUFF_IRQ_WATER_LVL_OFF);
+}
+
+uint8_t audio_i2s_mps3_get_rx_buff_water_lvl(struct audio_i2s_mps3_dev_t* dev){
+ struct audio_i2s_mps3_reg_map_t* p_i2s = (struct audio_i2s_mps3_reg_map_t*)dev->cfg->base;
+
+ return (uint8_t)((p_i2s->control >> AUDIO_I2S_MPS3_CONTROL_RX_BUFF_IRQ_WATER_LVL_OFF) & 0x7);
+}
diff --git a/partitions/vad_an552_sp/native_drivers/audio_i2s_mps3_drv.h b/partitions/vad_an552_sp/native_drivers/audio_i2s_mps3_drv.h
new file mode 100644
index 0000000..e16012f
--- /dev/null
+++ b/partitions/vad_an552_sp/native_drivers/audio_i2s_mps3_drv.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+/**
+ * \file audio_i2s_mps3_drv.h
+ *
+ * \brief Driver for Audio I2S
+ *
+ * The I2S interface supports transfer of digital audio to and
+ * from the Audio CODEC
+ *
+ * Main features:
+ * - Clear/Set Control Register bits to enable or disable buffer or interrupt
+ * and to reset Audio codec or FIFO
+ * - Check status of receive and transmit buffer
+ * - Get receive buffer data
+ * - Set transmit buffer data
+ * - Get Control, Status, Error register value
+ * - Write/Read sample
+ */
+
+#ifndef __AUDIO_I2S_MPS3_DRV_H__
+#define __AUDIO_I2S_MPS3_DRV_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Audio I2S device configuration structure
+ */
+struct audio_i2s_mps3_dev_cfg_t{
+ const uint32_t base;
+ /*!< Audio I2S device base address */
+};
+
+/**
+ * \brief Audio I2S device structure
+ */
+struct audio_i2s_mps3_dev_t {
+ const struct audio_i2s_mps3_dev_cfg_t* const cfg;
+ /*!< Audio I2S configuration structure */
+};
+
+/**
+ * \brief I2S audio sample structure
+ */
+struct audio_i2s_mps3_sample_t{
+ uint16_t left_channel;
+ uint16_t right_channel;
+};
+
+/**
+ * \brief Audio I2S error enumeration types
+ */
+enum audio_i2s_mps3_error_t{
+ AUDIO_I2S_MPS3_ERR_NONE = 0, /*!< No error */
+ AUDIO_I2S_MPS3_ERR_INVALID_ARG, /*!< Error invalid input argument */
+};
+
+/**
+ * \brief Reset Audio codec
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_set_codec_reset(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Reset FIFO
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_set_fifo_reset(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Clear Audio codec reset
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_clear_codec_reset(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Clear FIFO reset
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_clear_fifo_reset(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Checks if Receive Buffer is empty
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \return True if it is empty, False otherwise
+ */
+bool audio_i2s_mps3_is_rx_buffer_empty(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Checks if Receive Buffer is full
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \return True if it is full, False otherwise
+ */
+bool audio_i2s_mps3_is_rx_buffer_full(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Checks if Transmit Buffer is empty
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \return True if it is empty, False otherwise
+ */
+bool audio_i2s_mps3_is_tx_buffer_empty(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Checks if Transmit Buffer is full
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \return True if it is full, False otherwise
+ */
+bool audio_i2s_mps3_is_tx_buffer_full(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Sets clock divider value
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ * \param[in] lrdiv divide value
+ *
+ * \return Returns error code as specified in \ref audio_i2s_mps3_error_t
+ */
+enum audio_i2s_mps3_error_t audio_i2s_mps3_speed_config(struct audio_i2s_mps3_dev_t* dev, uint16_t lrdiv);
+
+/**
+ * \brief Get Receive Buffer FIFO Data Register
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \return Returns register value
+ */
+uint32_t audio_i2s_mps3_get_rxbuf(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Set Transmit Buffer Fifo Data Register
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ * \param[in] left_channel audio left channel value
+ * \param[in] right_channel audio right channel value
+ */
+void audio_i2s_mps3_set_txbuf(struct audio_i2s_mps3_dev_t* dev, uint16_t left_channel,
+ uint16_t right_channel);
+
+/**
+ * \brief Enable Receive Buffer
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_enable_rxbuf(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Enable Receive Interrupt
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_enable_rxinterrupt(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Enable Transmit Buffer
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_enable_txbuf(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Enable Transmit Interrupt
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_enable_txinterrupt(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Disable Receive Buffer
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_disable_rxbuf(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Disable Receive Interrupt
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_disable_rxinterrupt(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Disable Transmit Buffer
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_disable_txbuf(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Disable Transmit Interrupt
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ */
+void audio_i2s_mps3_disable_txinterrupt(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Get Control Register
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \return Returns register value
+ */
+uint32_t audio_i2s_mps3_get_control(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Get Status register
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \return Returns register value
+ */
+uint32_t audio_i2s_mps3_get_status(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Get Error Status Register
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \return Returns register value
+ */
+uint32_t audio_i2s_mps3_get_error(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Reads audio sample from Receive Buffer Register
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \returns Returns an audio_i2s_mps3_sample_t structure
+ */
+struct audio_i2s_mps3_sample_t read_sample(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Writes audio sample to Transmit Buffer Register
+ * *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ * \param[in] sample Value of an audio sample
+ */
+void write_sample(struct audio_i2s_mps3_dev_t* dev,
+ struct audio_i2s_mps3_sample_t sample);
+
+/**
+ * \brief Set Tx Buffer Interrupt Water Level
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ * \param[in] level Water level to be set (0-7)
+ */
+void audio_i2s_mps3_set_tx_buff_water_lvl(struct audio_i2s_mps3_dev_t* dev,
+ uint8_t level);
+
+/**
+ * \brief Get Tx Buffer Interrupt Water Level
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \returns Returns Tx Buffer Interrupt Water Level
+ */
+uint8_t audio_i2s_mps3_get_tx_buff_water_lvl(struct audio_i2s_mps3_dev_t* dev);
+
+/**
+ * \brief Set Rx Buffer Interrupt Water Level
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ * \param[in] level Water level to be set (0-7)
+ */
+void audio_i2s_mps3_set_rx_buff_water_lvl(struct audio_i2s_mps3_dev_t* dev,
+ uint8_t level);
+
+/**
+ * \brief Get Rx Buffer Interrupt Water Level
+ *
+ * \param[in] dev Audio I2S device struct \ref audio_i2s_mps3_dev_t
+ *
+ * \returns Returns Rx Buffer Interrupt Water Level
+ */
+uint8_t audio_i2s_mps3_get_rx_buff_water_lvl(struct audio_i2s_mps3_dev_t* dev);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __AUDIO_I2S_MPS3_DRV_H__ */
diff --git a/partitions/vad_an552_sp/native_drivers/i2c_sbcon_drv.c b/partitions/vad_an552_sp/native_drivers/i2c_sbcon_drv.c
new file mode 100644
index 0000000..4d95419
--- /dev/null
+++ b/partitions/vad_an552_sp/native_drivers/i2c_sbcon_drv.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2016-2018 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "i2c_sbcon_drv.h"
+
+#define SDA (1 << 1)
+#define SCL (1 << 0)
+#define I2C_HIGH(i2c_dev, pin) (i2c_dev->ctrl_reg.set = pin)
+#define I2C_LOW(i2c_dev, pin) (i2c_dev->clear_reg = pin)
+#define I2C_GET(i2c_dev, pin) ((i2c_dev->ctrl_reg.status >> (pin-1)) & 0x01)
+
+/* I2C SBCon state definitions */
+#define I2C_SBCON_INITIALIZED (1 << 0)
+
+/* I2C SBCon register map structure */
+struct i2c_sbcon_ctrl_t {
+ union {
+ /* Offset: 0x000 Control Status Register (r/ ) */
+ volatile uint32_t status;
+ /* Offset: 0x000 Control Set Register ( /w) */
+ volatile uint32_t set;
+ } ctrl_reg;
+ /* Offset: 0x004 Control Clear Register ( /w) */
+ volatile uint32_t clear_reg;
+};
+
+/*
+ * \brief Transmits a data bit.
+ *
+ * \param[in] dev Pointer to the I2C device \ref i2c_sbcon_dev_t
+ * \param[in] bit Bit to transmit.
+ */
+static void i2c_tx_bit(const struct i2c_sbcon_dev_t* dev,
+ uint8_t bit)
+{
+ struct i2c_sbcon_ctrl_t* p_i2c = (struct i2c_sbcon_ctrl_t*)dev->cfg->base;
+ if (bit != 0) {
+ I2C_HIGH(p_i2c, SDA);
+ } else {
+ I2C_LOW(p_i2c, SDA);
+ }
+
+ dev->cfg->sleep_us(dev->data->freq_us);
+
+ I2C_HIGH(p_i2c, SCL);
+ dev->cfg->sleep_us(dev->data->freq_us);
+
+ I2C_LOW(p_i2c, SCL);
+ dev->cfg->sleep_us(dev->data->freq_us);
+}
+
+/*
+ * \brief Reads a data bit
+ *
+ * \param[in] dev Pointer to the I2C device \ref i2c_sbcon_dev_t
+ *
+ * \returns Bit value received.
+ */
+static uint8_t i2c_rx_bit(const struct i2c_sbcon_dev_t* dev)
+{
+ uint8_t bit;
+ struct i2c_sbcon_ctrl_t* p_i2c = (struct i2c_sbcon_ctrl_t*)dev->cfg->base;
+
+ I2C_HIGH(p_i2c, SDA);
+ dev->cfg->sleep_us(dev->data->freq_us);
+
+ I2C_HIGH(p_i2c, SCL);
+ dev->cfg->sleep_us(dev->data->freq_us);
+
+ bit = I2C_GET(p_i2c, SDA);
+
+ I2C_LOW(p_i2c, SCL);
+ dev->cfg->sleep_us(dev->data->freq_us);
+
+ return bit;
+}
+
+enum i2c_sbcon_error_t i2c_sbcon_init(struct i2c_sbcon_dev_t* dev,
+ uint32_t sys_clk)
+{
+ if (sys_clk == 0) {
+ return I2C_ERR_INVALID_ARG;
+ }
+
+ dev->data->sys_clk = sys_clk;
+
+ dev->data->freq_us = (sys_clk / dev->cfg->default_freq_hz);
+
+ dev->data->state = I2C_SBCON_INITIALIZED;
+
+ return I2C_ERR_NONE;
+}
+
+enum i2c_sbcon_error_t i2c_sbcon_reset(struct i2c_sbcon_dev_t* dev)
+{
+ uint32_t iter;
+ uint32_t freq_us = dev->data->freq_us;
+ struct i2c_sbcon_ctrl_t* p_i2c = (struct i2c_sbcon_ctrl_t*)dev->cfg->base;
+
+ if(!(dev->data->state & I2C_SBCON_INITIALIZED)) {
+ return I2C_ERR_NOT_INIT;
+ }
+
+ /* The reset sequence is:
+ * - SDA line low
+ * - 9 clock pulses
+ * - SDA line high
+ */
+ I2C_LOW(p_i2c, SDA);
+ dev->cfg->sleep_us(freq_us);
+
+ for(iter=0; iter < 9; iter++) {
+ I2C_LOW(p_i2c, SCL);
+ dev->cfg->sleep_us(freq_us);
+ I2C_HIGH(p_i2c, SCL);
+ dev->cfg->sleep_us(freq_us);
+ }
+
+ I2C_HIGH(p_i2c, SDA);
+ dev->cfg->sleep_us(freq_us);
+
+ return I2C_ERR_NONE;
+}
+
+enum i2c_sbcon_error_t i2c_sbcon_set_freq(struct i2c_sbcon_dev_t* dev,
+ uint32_t i2c_hz)
+{
+ if (dev->data->sys_clk < i2c_hz || i2c_hz == 0) {
+ return I2C_ERR_INVALID_ARG;
+ }
+
+ if(!(dev->data->state & I2C_SBCON_INITIALIZED)) {
+ return I2C_ERR_NOT_INIT;
+ }
+
+ dev->data->freq_us = (dev->data->sys_clk / i2c_hz);
+
+ return I2C_ERR_NONE;
+}
+
+uint32_t i2c_sbcon_get_freq(struct i2c_sbcon_dev_t* dev)
+{
+ if(!(dev->data->state & I2C_SBCON_INITIALIZED)) {
+ return 0;
+ }
+
+ return (dev->data->freq_us * dev->data->sys_clk);
+}
+
+enum i2c_sbcon_error_t i2c_sbcon_set_sys_clk( struct i2c_sbcon_dev_t* dev,
+ uint32_t sys_clk)
+{
+ uint32_t i2c_hz;
+
+ if (sys_clk == 0) {
+ return I2C_ERR_INVALID_ARG;
+ }
+
+ if(!(dev->data->state & I2C_SBCON_INITIALIZED)) {
+ return I2C_ERR_NOT_INIT;
+ }
+
+ /* Gets I2C frequency in Hz */
+ i2c_hz = dev->data->freq_us * dev->data->sys_clk;
+
+ /* Saves new system clock value */
+ dev->data->sys_clk = sys_clk;
+
+ /* Saves the I2C frequencu in us */
+ dev->data->freq_us = (dev->data->sys_clk / i2c_hz);
+
+ return I2C_ERR_NONE;
+}
+
+void i2c_sbcon_tx_start(const struct i2c_sbcon_dev_t* dev)
+{
+ struct i2c_sbcon_ctrl_t* p_i2c = (struct i2c_sbcon_ctrl_t*)dev->cfg->base;
+
+ /* SDA goes from HIGH to LOW while SCL is HIGH */
+ I2C_HIGH(p_i2c, (SCL | SDA));
+ dev->cfg->sleep_us(dev->data->freq_us);
+
+ I2C_LOW(p_i2c, SDA);
+ dev->cfg->sleep_us(dev->data->freq_us);
+
+ I2C_LOW(p_i2c, SCL);
+ dev->cfg->sleep_us(dev->data->freq_us);
+}
+
+void i2c_sbcon_tx_stop(const struct i2c_sbcon_dev_t* dev)
+{
+ struct i2c_sbcon_ctrl_t* p_i2c = (struct i2c_sbcon_ctrl_t*)dev->cfg->base;
+
+ /* SDA goes from LOW to HIGH while SCL is HIGH */
+ I2C_LOW(p_i2c, SDA);
+ dev->cfg->sleep_us(dev->data->freq_us);
+
+ I2C_HIGH(p_i2c, SCL);
+ dev->cfg->sleep_us(dev->data->freq_us);
+
+ I2C_HIGH(p_i2c, SDA);
+ dev->cfg->sleep_us(dev->data->freq_us);
+}
+
+void i2c_sbcon_tx_ack(const struct i2c_sbcon_dev_t* dev, uint8_t ack)
+{
+ i2c_tx_bit(dev, ack);
+}
+
+void i2c_sbcon_tx_byte(const struct i2c_sbcon_dev_t* dev, uint8_t data)
+{
+ uint8_t nbr_bits ;
+
+ for(nbr_bits=0; nbr_bits < 8; nbr_bits++) {
+ i2c_tx_bit(dev, data & 0x80);
+ data <<= 1;
+ }
+}
+
+uint8_t i2c_sbcon_rx_ack(const struct i2c_sbcon_dev_t* dev)
+{
+ uint8_t ack;
+
+ ack = i2c_rx_bit(dev);
+
+ return ack;
+}
+
+uint8_t i2c_sbcon_rx_byte(struct i2c_sbcon_dev_t* dev)
+{
+ uint8_t numBits;
+ uint8_t data = 0;
+
+ for (numBits = 0; numBits < 8; numBits++) {
+ data <<= 1;
+ data |= i2c_rx_bit(dev);
+ }
+
+ return data;
+}
+
+enum i2c_sbcon_error_t i2c_sbcon_master_transmit(
+ struct i2c_sbcon_dev_t* dev,
+ uint16_t addr,
+ const uint8_t* data,
+ uint32_t len,
+ uint8_t xfer_pending,
+ uint32_t* nbr_bytes_write)
+{
+ i2c_sbcon_tx_start(dev);
+
+ i2c_sbcon_tx_byte(dev, (uint8_t) addr);
+ i2c_sbcon_rx_ack(dev);
+
+ if(addr & I2C_10BIT) {
+ i2c_sbcon_tx_byte(dev, (uint8_t)(addr >> 8));
+ i2c_sbcon_rx_ack(dev);
+ }
+
+ for (*nbr_bytes_write = 0; *nbr_bytes_write < len; (*nbr_bytes_write)++) {
+ i2c_sbcon_tx_byte(dev, data[*nbr_bytes_write]);
+ i2c_sbcon_rx_ack(dev);
+ }
+
+ if (!xfer_pending) {
+ i2c_sbcon_tx_stop(dev);
+ }
+
+ return I2C_ERR_NONE;
+}
+
+enum i2c_sbcon_error_t i2c_sbcon_master_receive(
+ struct i2c_sbcon_dev_t* dev,
+ uint16_t addr, uint8_t* data,
+ uint32_t len,
+ uint8_t xfer_pending,
+ uint32_t* nbr_bytes_read)
+{
+ i2c_sbcon_tx_start(dev);
+
+ i2c_sbcon_tx_byte(dev, (uint8_t) (addr | 0x1));
+ i2c_sbcon_rx_ack(dev);
+
+ if(addr & I2C_10BIT) {
+ i2c_sbcon_tx_byte(dev, (uint8_t)(addr >> 8));
+ i2c_sbcon_rx_ack(dev);
+ }
+
+ data[0] = i2c_sbcon_rx_byte(dev);
+ for (*nbr_bytes_read = 1; *nbr_bytes_read < len; (*nbr_bytes_read)++) {
+ i2c_sbcon_tx_ack(dev, 0);
+ data[*nbr_bytes_read] = i2c_sbcon_rx_byte(dev);
+ }
+ i2c_sbcon_tx_ack(dev, 1);
+
+ if (!xfer_pending) {
+ i2c_sbcon_tx_stop(dev);
+ }
+
+ return I2C_ERR_NONE;
+}
diff --git a/partitions/vad_an552_sp/native_drivers/i2c_sbcon_drv.h b/partitions/vad_an552_sp/native_drivers/i2c_sbcon_drv.h
new file mode 100644
index 0000000..b4487aa
--- /dev/null
+++ b/partitions/vad_an552_sp/native_drivers/i2c_sbcon_drv.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2016-2018 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file i2c_sbcon_drv.h
+ * \brief Generic driver for I2C SBCon.
+ * The I2C SBCon IP requires a bit banging programing model.
+ */
+
+#ifndef __I2C_SBCON_DRV_H__
+#define __I2C_SBCON_DRV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#define I2C_10BIT 0x0400
+
+/**
+ * \brief Sleeps for a given amount of microseconds.
+ *
+ * \param[in] us Microseconds to sleep.
+ */
+typedef void SLEEP_US(uint32_t us);
+
+/* I2C SBCon device configuration structure */
+struct i2c_sbcon_dev_cfg_t {
+ const uint32_t base; /*!< I2C SBCon base address */
+ const uint32_t default_freq_hz; /*!< Operational frequence in Hz */
+ SLEEP_US* const sleep_us; /*!< Sleep function in us */
+};
+
+/* I2C SBCon device data structure */
+struct i2c_sbcon_dev_data_t {
+ uint32_t freq_us; /*!< Operational frequence in us */
+ uint32_t sys_clk; /*!< System clock frequency */
+ uint32_t state; /*!< Indicates if the I2C SBCon driver
+ is initialized */
+};
+
+/* I2C SBCon device structure */
+struct i2c_sbcon_dev_t {
+ const struct i2c_sbcon_dev_cfg_t* const cfg; /*!< I2C SBCon
+ configuration */
+ struct i2c_sbcon_dev_data_t* const data; /*!< I2C SBCon data */
+};
+
+/* Error codes returned by the driver functions */
+enum i2c_sbcon_error_t {
+ I2C_ERR_NONE, /*!< No error */
+ I2C_ERR_INVALID_ARG, /*!< I2C invalid input arguments */
+ I2C_ERR_NOT_INIT, /*!< I2C not initialized */
+};
+
+/**
+ * \brief Initializes I2C controller.
+ *
+ * \param[in] dev I2C device struct \ref i2c_sbcon_dev_t
+ * \param[in] sys_clk System clock frequency.
+ *
+ * \return Returns error code as specified in \ref i2c_sbcon_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum i2c_sbcon_error_t i2c_sbcon_init(struct i2c_sbcon_dev_t* dev,
+ uint32_t sys_clk);
+
+/**
+ * \brief Resets I2C controller.
+ *
+ * \param[in] dev I2C device struct \ref i2c_sbcon_dev_t
+ *
+ * \return Returns error code as specified in \ref i2c_sbcon_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum i2c_sbcon_error_t i2c_sbcon_reset(struct i2c_sbcon_dev_t* dev);
+
+/**
+ * \brief Sets I2C speed.
+ *
+ * \param[in] dev I2C device struct \ref i2c_sbcon_dev_t
+ * \param[in] i2c_hz I2C frequency in Hz.
+ *
+ * \return Returns error code as specified in \ref i2c_sbcon_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum i2c_sbcon_error_t i2c_sbcon_set_freq(
+ struct i2c_sbcon_dev_t* dev,
+ uint32_t i2c_hz);
+
+/**
+ * \brief Gets I2C speed.
+ *
+ * \param[in] dev I2C device struct \ref i2c_sbcon_dev_t
+ *
+ * \return Returns I2C frequency in Hz.
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+uint32_t i2c_sbcon_get_freq(struct i2c_sbcon_dev_t* dev);
+
+/**
+ * \brief Sets system clock frequency.
+ *
+ * \param[in] dev I2C device struct \ref i2c_sbcon_dev_t
+ * \param[in] sys_clk System clock frequency.
+ *
+ * \return Returns error code as specified in \ref i2c_sbcon_error_t
+ *
+ * \note This function doesn't check if dev is NULL.
+ */
+enum i2c_sbcon_error_t i2c_sbcon_set_sys_clk(
+ struct i2c_sbcon_dev_t* dev,
+ uint32_t sys_clk);
+
+/*
+ * \brief Transmits start bit.
+ *
+ * \param[in] dev Pointer to the I2C device \ref i2c_sbcon_dev_t
+ *
+ * \note For better performance, this function doesn't check if the driver is
+ * initialized.
+ */
+void i2c_sbcon_tx_start(const struct i2c_sbcon_dev_t* dev);
+
+/*
+ * \brief Transmits stop bit.
+ *
+ * \param[in] dev Pointer to the I2C device \ref i2c_sbcon_dev_t
+ *
+ * \note For better performance, this function doesn't check if the driver is
+ * initialized.
+ */
+void i2c_sbcon_tx_stop(const struct i2c_sbcon_dev_t* dev);
+
+/*
+ * \brief Writes acknowledge bit.
+ *
+ * \param[in] dev Pointer to the I2C device \ref i2c_sbcon_dev_t
+ * \param[in] ack Ack bit to write.
+ *
+ * \note For better performance, this function doesn't check if the driver is
+ * initialized.
+ */
+void i2c_sbcon_tx_ack(const struct i2c_sbcon_dev_t* dev, uint8_t ack);
+
+/*
+ * \brief Transmits a byte.
+ *
+ * \param[in] dev Pointer to the I2C device \ref i2c_sbcon_dev_t
+ * \param[in] data Byte to transmit.
+ *
+ * \note For better performance, this function doesn't check if the driver is
+ * initialized.
+ */
+void i2c_sbcon_tx_byte(const struct i2c_sbcon_dev_t* dev, uint8_t data);
+
+/*
+ * \brief Reads acknowledge bit
+ *
+ * \param[in] dev Pointer to the I2C device \ref i2c_sbcon_dev_t
+ *
+ * \returns Bit value received.
+ *
+ * \note For better performance, this function doesn't check if the driver is
+ * initialized.
+ */
+uint8_t i2c_sbcon_rx_ack(const struct i2c_sbcon_dev_t* dev);
+
+/*
+ * \brief Reads a byte.
+ *
+ * \param[in] dev Pointer to the I2C device \ref i2c_sbcon_dev_t
+ *
+ * \returns byte value received.
+ *
+ * \note For better performance, this function doesn't check if the driver is
+ * initialized.
+ */
+uint8_t i2c_sbcon_rx_byte(struct i2c_sbcon_dev_t* dev);
+
+/**
+ * \brief Writes data to I2C device.
+ *
+ * \param[in] dev I2C device struct \ref i2c_sbcon_dev_t
+ * \param[in] addr I2C device address (7 bits or 10 bits).
+ * The value can be ORed with I2C_10BIT to
+ * identify a 10-bit address value.
+ * \param[in] data Buffer pointer to store the read data.
+ * \param[in] len Buffer length.
+ * \param[in] xfer_pending Transfer operation is pending, stop condition
+ * will not be generated
+ * \param[out] nbr_bytes_write Number of bytes written
+ *
+ * \return Returns error code as specified in \ref i2c_sbcon_error_t
+ *
+ * \note For better performance, this function doesn't check if the pointers
+ * are NULL and if the driver is initialized.
+ * If it is on 7 bits, the addr argument has to be shifted by 1 bit to the
+ * left before being sent to the function. The least significant bit will
+ * be used to specify READ or WRITE.
+ */
+enum i2c_sbcon_error_t i2c_sbcon_master_transmit(
+ struct i2c_sbcon_dev_t* dev,
+ uint16_t addr, const uint8_t *data,
+ uint32_t len, uint8_t xfer_pending,
+ uint32_t* nbr_bytes_write);
+
+/**
+ * \brief Reads data from I2C device.
+ *
+ * \param[in] dev I2C device struct \ref i2c_sbcon_dev_t
+ * \param[in] addr I2C device address (7 bits or 10 bits).
+ * The value can be ORed with I2C_10BIT to
+ * identify a 10-bit address value.
+ * \param[out] data Buffer pointer to store the read data.
+ * \param[in] len Buffer length.
+ * \param[in] xfer_pending Transfer operation is pending, stop condition
+ * will not be generated
+ * \param[out] nbr_bytes_read Number of bytes read
+ *
+ * \return Returns error code as specified in \ref i2c_sbcon_error_t
+ *
+ * \note For better performance, this function doesn't check if the pointers
+ * are NULL and if the driver is initialized.
+ * If it is on 7 bits, the addr argument has to be shifted by 1 bit to the
+ * left before being sent to the function. The least significant bit will
+ * be used to specify READ or WRITE.
+ */
+enum i2c_sbcon_error_t i2c_sbcon_master_receive(
+ struct i2c_sbcon_dev_t* dev,
+ uint16_t addr, uint8_t *data,
+ uint32_t len,
+ uint8_t xfer_pending,
+ uint32_t* nbr_bytes_read);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __I2C_SBCON_DRV_H__ */
diff --git a/partitions/vad_an552_sp/ns_interface/vad_an552.h b/partitions/vad_an552_sp/ns_interface/vad_an552.h
new file mode 100644
index 0000000..bfadfb2
--- /dev/null
+++ b/partitions/vad_an552_sp/ns_interface/vad_an552.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __VAD_API_H__
+#define __VAD_API_H__
+
+#include <stdint.h>
+
+#include "psa/error.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \bried Status of the voice activity detection algorithm
+ */
+#define VAD_STOPPED (0u)
+#define VAD_NO_VOICE_DETECTED (1u)
+#define VAD_RECORDING (2u)
+#define VAD_VOICE_RECORDED (3u)
+
+/**
+ * \brief Starts running voice activity detection algorithm on the microphone
+ * input.
+ *
+ * Microphone samples are processed in interrupt context. If voice activity is
+ * detected the partition starts recording a short sample.
+ *
+ * \return Returns values as specified by the \ref psa_status_t
+ */
+psa_status_t vad_an552_start_vad(void);
+
+/**
+ * \brief Queries the status of the voice activity detection algorithm.
+ *
+ * \param[out] vad_status If no voice activity was detected since the
+ * algorithm was started \ref VAD_VOICE_DETECTED is
+ * given back, if the recording is running
+ * \ref VAD_RECORDING, otherwise
+ * \ref VAD_VOICE_RECORDED.
+ *
+ * \return Returns values as specified by the \ref psa_status_t
+ */
+psa_status_t vad_an552_query_vad(uint32_t *vad_status);
+
+/**
+ * \brief Returns the frequency of the recorded smaple.
+ *
+ * \param[out] freq The frequency component with the most energy.
+ *
+ * \return Returns values as specified by the \ref psa_status_t
+ */
+psa_status_t vad_an552_get_freq(uint32_t *freq);
+
+/**
+ * \brief Stops the running voice activity detection algorithm.
+ *
+ * \return Returns values as specified by the \ref psa_status_t
+ */
+psa_status_t vad_an552_stop_vad(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VAD_API_H__ */
diff --git a/partitions/vad_an552_sp/ns_interface/vad_an552_defs.h b/partitions/vad_an552_sp/ns_interface/vad_an552_defs.h
new file mode 100644
index 0000000..0cc4d32
--- /dev/null
+++ b/partitions/vad_an552_sp/ns_interface/vad_an552_defs.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __VAD_AN552_DEFS_H__
+#define __VAD_AN552_DEFS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Message types that distinguish VAD services. */
+#define VAD_AN552_START 1001
+#define VAD_AN552_QUERY 1002
+#define VAD_AN552_GET_FREQ 1003
+#define VAD_AN552_STOP 1004
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VAD_AN552_DEFS_H__ */
diff --git a/partitions/vad_an552_sp/ns_interface/vad_an552_ipc_api.c b/partitions/vad_an552_sp/ns_interface/vad_an552_ipc_api.c
new file mode 100644
index 0000000..b66d8c6
--- /dev/null
+++ b/partitions/vad_an552_sp/ns_interface/vad_an552_ipc_api.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "vad_an552.h"
+
+#include "psa/client.h"
+#include "psa_manifest/sid.h"
+#include "vad_an552_defs.h"
+
+psa_status_t vad_an552_start_vad(void)
+{
+ psa_status_t status;
+
+ status = psa_call(TFM_AN552_VAD_HANDLE, VAD_AN552_START,
+ NULL, 0, NULL, 0);
+
+ return status;
+}
+
+psa_status_t vad_an552_query_vad(uint32_t* vad_status)
+{
+ psa_status_t status;
+ psa_outvec out_vec[] = {
+ {.base = vad_status, .len = sizeof(uint32_t)}
+ };
+
+ status = psa_call(TFM_AN552_VAD_HANDLE, VAD_AN552_QUERY,
+ NULL, 0, out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+psa_status_t vad_an552_get_freq(uint32_t* freq)
+{
+ psa_status_t status;
+ psa_outvec out_vec[] = {
+ {.base = freq, .len = sizeof(uint32_t)}
+ };
+
+ status = psa_call(TFM_AN552_VAD_HANDLE, VAD_AN552_GET_FREQ,
+ NULL, 0, out_vec, IOVEC_LEN(out_vec));
+
+ return status;
+}
+
+psa_status_t vad_an552_stop_vad(void)
+{
+ psa_status_t status;
+
+ status = psa_call(TFM_AN552_VAD_HANDLE, VAD_AN552_STOP,
+ NULL, 0, NULL, 0);
+
+ return status;
+}
diff --git a/partitions/vad_an552_sp/vad_an552_device_definition.c b/partitions/vad_an552_sp/vad_an552_device_definition.c
new file mode 100644
index 0000000..7a66b63
--- /dev/null
+++ b/partitions/vad_an552_sp/vad_an552_device_definition.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021-2022 Arm Limited. All rights reserved.
+ *
+ * Licensed under the Apache License Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "vad_an552_device_definition.h"
+#include "platform_base_address.h"
+#include "timeout.h"
+
+static const struct systimer_armv8_m_dev_cfg_t
+SYSTIMER3_ARMV8_M_DEV_CFG_S = {
+ .base = SYSTIMER3_ARMV8_M_BASE_S,
+ .default_freq_hz = SYSTIMER3_ARMV8M_DEFAULT_FREQ_HZ
+};
+static struct systimer_armv8_m_dev_data_t
+SYSTIMER3_ARMV8_M_DEV_DATA_S = {
+ .is_initialized = false
+};
+struct systimer_armv8_m_dev_t SYSTIMER3_ARMV8_M_DEV_S = {
+ &(SYSTIMER3_ARMV8_M_DEV_CFG_S),
+ &(SYSTIMER3_ARMV8_M_DEV_DATA_S)
+};
+
+static struct i2c_sbcon_dev_cfg_t I2C0_SBCON_DEV_CFG_S = {
+ .base = FPGA_SBCon_I2C_AUDIO_BASE_S,
+ .default_freq_hz = 100000,
+ .sleep_us = &wait_us
+};
+static struct i2c_sbcon_dev_data_t I2C0_SBCON_DEV_DATA_S ={
+ .freq_us = 0,
+ .sys_clk = 0,
+ .state = 0
+};
+struct i2c_sbcon_dev_t I2C0_SBCON_DEV_S = {
+ .cfg = &(I2C0_SBCON_DEV_CFG_S),
+ .data = &(I2C0_SBCON_DEV_DATA_S)
+};
+
+static const struct audio_i2s_mps3_dev_cfg_t MPS3_I2S_DEV_CFG_S = {
+ .base = FPGA_I2S_BASE_S
+};
+struct audio_i2s_mps3_dev_t MPS3_I2S_DEV_S = {
+ &(MPS3_I2S_DEV_CFG_S),
+};
diff --git a/partitions/vad_an552_sp/vad_an552_device_definition.h b/partitions/vad_an552_sp/vad_an552_device_definition.h
new file mode 100644
index 0000000..7542c04
--- /dev/null
+++ b/partitions/vad_an552_sp/vad_an552_device_definition.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021-2022 Arm Limited. All rights reserved.
+ *
+ * Licensed under the Apache License Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing software
+ * distributed under the License is distributed on an "AS IS" BASIS
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __VAD_AN552_DEVICE_DEFINITION_H__
+#define __VAD_AN552_DEVICE_DEFINITION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SYSTIMER3_ARMV8M_DEFAULT_FREQ_HZ (32000000ul)
+
+#include "systimer_armv8-m_drv.h"
+extern struct systimer_armv8_m_dev_t SYSTIMER3_ARMV8_M_DEV_S;
+
+#include "i2c_sbcon_drv.h"
+extern struct i2c_sbcon_dev_t I2C0_SBCON_DEV_S;
+
+#include "audio_i2s_mps3_drv.h"
+extern struct audio_i2s_mps3_dev_t MPS3_I2S_DEV_S;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VAD_AN552_DEVICE_DEFINITION_H__ */
diff --git a/partitions/vad_an552_sp/vad_an552_sp.yaml b/partitions/vad_an552_sp/vad_an552_sp.yaml
new file mode 100644
index 0000000..5a33eed
--- /dev/null
+++ b/partitions/vad_an552_sp/vad_an552_sp.yaml
@@ -0,0 +1,47 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+
+{
+ "psa_framework_version": 1.1,
+ "name": "TFM_SP_VAD_AN552",
+ "type": "APPLICATION-ROT",
+ "priority": "NORMAL",
+ "model": "IPC",
+ "entry_point": "vad_main",
+ "stack_size": "0x1000",
+ "services": [
+ {
+ "name": "TFM_AN552_VAD",
+ "sid": "0x00000100",
+ "connection_based": false,
+ "non_secure_clients": true,
+ "version": 1,
+ "version_policy": "STRICT"
+ }
+ ],
+ "irqs": [
+ {
+ "source": "I2S_IRQn",
+ "name": "I2S",
+ "handling": "FLIH",
+ }
+ ],
+ "mmio_regions": [
+ {
+ "name": "TFM_PERIPHERAL_FPGA_I2S",
+ "permission": "READ-WRITE"
+ },
+ {
+ "name": "TFM_PERIPHERAL_AUDIO_I2C",
+ "permission": "READ-WRITE"
+ },
+ {
+ "name": "TFM_PERIPHERAL_TIMER3",
+ "permission": "READ-WRITE"
+ }
+ ]
+}
diff --git a/partitions/vad_an552_sp/vad_an552_sp_main.c b/partitions/vad_an552_sp/vad_an552_sp_main.c
new file mode 100644
index 0000000..eae8f96
--- /dev/null
+++ b/partitions/vad_an552_sp/vad_an552_sp_main.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+
+#include "psa/service.h"
+#include "psa_manifest/vad_an552_sp.h"
+#include "vad_an552_defs.h"
+#include "vad_an552.h"
+#include "timeout.h"
+#include "tfm_sp_log.h"
+#include "vad_an552_device_definition.h"
+#include "audio_codec_mps3.h"
+#include "cmsis.h"
+#include "tfm_peripherals_def.h"
+
+/* CMSIS DSP implementations */
+#include "dsp/statistics_functions.h"
+#include "dsp/transform_functions.h"
+#include "dsp/complex_math_functions.h"
+
+/* Voice activity detection algorithm and related defines */
+extern void vad_estimation(long *command, long* vad, short *inputData,
+ long nbSamples, long samplingRate);
+#define INIT_VAD 1
+#define PROC_VAD 2
+#define FS 48000
+
+/* For voice recording and FFT calculation */
+#define RECORDING_SIZE 4096
+int16_t sample_buffer[RECORDING_SIZE];
+uint32_t sample_buffer_end_idx; /* Index of last element in sample_buffer */
+q15_t fft_result[2 * RECORDING_SIZE];
+q15_t fft_magnitude[RECORDING_SIZE];
+
+/* Status of the secure partition */
+uint32_t vad_status = VAD_STOPPED;
+
+void start_listening()
+{
+ audio_i2s_mps3_set_fifo_reset(&MPS3_I2S_DEV_S);
+ wait_ms(1);
+ audio_i2s_mps3_clear_fifo_reset(&MPS3_I2S_DEV_S);
+ audio_i2s_mps3_enable_rxbuf(&MPS3_I2S_DEV_S);
+ audio_i2s_mps3_enable_rxinterrupt(&MPS3_I2S_DEV_S);
+}
+
+void stop_listening()
+{
+ audio_i2s_mps3_disable_rxbuf(&MPS3_I2S_DEV_S);
+ audio_i2s_mps3_disable_rxinterrupt(&MPS3_I2S_DEV_S);
+ wait_ms(1);
+}
+
+psa_flih_result_t i2s_flih(void)
+{
+ short current_sample;
+ long voice_activity = 0;
+ static long command = PROC_VAD;
+
+ while (audio_i2s_mps3_is_rx_buffer_empty(&MPS3_I2S_DEV_S) == false) {
+ /* Only right channel used, left channel is dropped with the casting */
+ current_sample = (short) audio_i2s_mps3_get_rxbuf(&MPS3_I2S_DEV_S);
+ if (vad_status == VAD_NO_VOICE_DETECTED) {
+ vad_estimation(&command, &voice_activity, ¤t_sample, 1, FS);
+
+ if (voice_activity == 1) {
+ vad_status = VAD_RECORDING;
+ sample_buffer_end_idx = 0;
+ }
+
+ } else if (vad_status == VAD_RECORDING){
+ sample_buffer[sample_buffer_end_idx++] = current_sample;
+
+ if (sample_buffer_end_idx ==
+ (sizeof(sample_buffer) / sizeof(sample_buffer[0]))) {
+ stop_listening();
+ vad_status = VAD_VOICE_RECORDED;
+ }
+ } else {
+ stop_listening();
+ }
+ }
+
+ return PSA_FLIH_NO_SIGNAL;
+}
+
+static psa_status_t start_vad()
+{
+ long command = INIT_VAD;
+
+ vad_estimation(&command, 0, 0, 0, FS);
+ vad_status = VAD_NO_VOICE_DETECTED;
+ start_listening();
+ psa_irq_enable(I2S_SIGNAL);
+
+ return PSA_SUCCESS;
+}
+
+static psa_status_t query_vad(const psa_msg_t *msg)
+{
+ psa_write(msg->handle, 0, &vad_status, sizeof(vad_status));
+
+ return PSA_SUCCESS;
+}
+
+static psa_status_t get_freq(const psa_msg_t *msg)
+{
+ uint32_t freq = 0;
+ arm_rfft_instance_q15 fft_instance;
+ arm_status dsp_status;
+ q15_t max_value;
+ uint32_t max_index;
+
+ if (vad_status == VAD_VOICE_RECORDED) {
+ dsp_status = arm_rfft_init_q15(&fft_instance, RECORDING_SIZE, 0, 1);
+
+ /* No need for conversation between int16_t and q15_t as we are only
+ * interested in which frequency bin has the highest energy.
+ */
+ arm_rfft_q15(&fft_instance, (q15_t *) sample_buffer, fft_result);
+ arm_cmplx_mag_q15(fft_result, fft_magnitude, RECORDING_SIZE);
+ arm_max_q15(fft_magnitude, RECORDING_SIZE/2, &max_value, &max_index);
+
+ if (max_value != 0) {
+ /* A real maximum was found, returning the lower end of the maximum
+ * frequency bin.
+ */
+ freq = (FS / RECORDING_SIZE) * max_index;
+ } else {
+ freq = 0;
+ }
+
+ psa_write(msg->handle, 0, &freq, sizeof(freq));
+
+ /* The FFT calculation updates the recorded sample, so we move to the
+ * intitial state.
+ */
+ vad_status = VAD_STOPPED;
+
+ return PSA_SUCCESS;
+ } else {
+ return PSA_ERROR_BAD_STATE;
+ }
+}
+
+static psa_status_t stop_vad()
+{
+ psa_irq_disable(I2S_SIGNAL);
+ stop_listening();
+ vad_status = VAD_STOPPED;
+
+ return PSA_SUCCESS;
+}
+
+static void vad_signal_handle(psa_signal_t signal)
+{
+ psa_msg_t msg;
+ psa_status_t status;
+
+ status = psa_get(signal, &msg);
+ if (status != PSA_SUCCESS) {
+ return;
+ }
+
+ switch (msg.type) {
+ case VAD_AN552_START:
+ status = start_vad();
+ psa_reply(msg.handle, status);
+ break;
+ case VAD_AN552_QUERY:
+ status = query_vad(&msg);
+ psa_reply(msg.handle, status);
+ break;
+ case VAD_AN552_GET_FREQ:
+ status = get_freq(&msg);
+ psa_reply(msg.handle, status);
+ break;
+ case VAD_AN552_STOP:
+ status = stop_vad();
+ psa_reply(msg.handle, status);
+ break;
+ default:
+ /* Invalid message type */
+ status = PSA_ERROR_PROGRAMMER_ERROR;
+ psa_reply(msg.handle, status);
+ break;
+ }
+}
+
+void vad_main(void)
+{
+ psa_signal_t signals;
+
+ /* Audio initialization */
+ audio_codec_mps3_init(&I2C0_SBCON_DEV_S, &MPS3_I2S_DEV_S);
+
+ /* Set Rx Buffer Irq Water Level. If less than 1 word space is available,
+ IRQ is triggered */
+ audio_i2s_mps3_set_rx_buff_water_lvl(&MPS3_I2S_DEV_S, 1);
+
+ LOG_DBGFMT("[VAD] Secure partition initialized\r\n");
+
+ while (1) {
+ signals = psa_wait(PSA_WAIT_ANY, PSA_BLOCK);
+
+ if (signals & TFM_AN552_VAD_SIGNAL) {
+ vad_signal_handle(TFM_AN552_VAD_SIGNAL);
+ } else {
+ psa_panic();
+ }
+ }
+}