diff --git a/BSP/audio.h b/BSP/audio.h
new file mode 100644
index 0000000..8b93673
--- /dev/null
+++ b/BSP/audio.h
@@ -0,0 +1,122 @@
+/**
+ ******************************************************************************
+ * @file audio.h
+ * @author MCD Application Team
+ * @version V4.0.1
+ * @date 21-July-2015
+ * @brief This header file contains the common defines and functions prototypes
+ * for the Audio driver.
+ ******************************************************************************
+ * @attention
+ *
+ *
© COPYRIGHT(c) 2015 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __AUDIO_H
+#define __AUDIO_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+#include
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup Components
+ * @{
+ */
+
+/** @addtogroup AUDIO
+ * @{
+ */
+
+/** @defgroup AUDIO_Exported_Constants
+ * @{
+ */
+
+/* Codec audio Standards */
+#define CODEC_STANDARD 0x04
+#define I2S_STANDARD I2S_STANDARD_PHILIPS
+
+/**
+ * @}
+ */
+
+/** @defgroup AUDIO_Exported_Types
+ * @{
+ */
+
+/** @defgroup AUDIO_Driver_structure Audio Driver structure
+ * @{
+ */
+typedef struct
+{
+ uint32_t (*Init)(uint16_t, uint16_t, uint8_t, uint32_t);
+ void (*DeInit)(void);
+ uint32_t (*ReadID)(uint16_t);
+ uint32_t (*Play)(uint16_t, uint16_t*, uint16_t);
+ uint32_t (*Pause)(uint16_t);
+ uint32_t (*Resume)(uint16_t);
+ uint32_t (*Stop)(uint16_t, uint32_t);
+ uint32_t (*SetFrequency)(uint16_t, uint32_t);
+ uint32_t (*SetVolume)(uint16_t, uint8_t);
+ uint32_t (*SetMute)(uint16_t, uint32_t);
+ uint32_t (*SetOutputMode)(uint16_t, uint8_t);
+ uint32_t (*Reset)(uint16_t);
+}AUDIO_DrvTypeDef;
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AUDIO_H */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/BSP/stm32f769i_discovery.c b/BSP/stm32f769i_discovery.c
new file mode 100644
index 0000000..44ee430
--- /dev/null
+++ b/BSP/stm32f769i_discovery.c
@@ -0,0 +1,800 @@
+/**
+ ******************************************************************************
+ * @file stm32f769i_discovery.c
+ * @author MCD Application Team
+ * @brief This file provides a set of firmware functions to manage LEDs,
+ * push-buttons, external SDRAM, external QSPI Flash, RF EEPROM,
+ * available on STM32F769I-Discovery board (MB1225) from
+ * STMicroelectronics.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2016 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Dependencies
+- stm32f7xx_hal_cortex.c
+- stm32f7xx_hal_gpio.c
+- stm32f7xx_hal_uart.c
+- stm32f7xx_hal_i2c.c
+EndDependencies */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f769i_discovery.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32F769I_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL STM32F769I_DISCOVERY LOW LEVEL
+ * @{
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_TypesDefinitions STM32F769I Discovery Low Level Private Typedef
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_Defines LOW_LEVEL Private Defines
+ * @{
+ */
+/**
+ * @brief STM32F769I Discovery BSP Driver version number V2.0.2
+ */
+#define __STM32F769I_DISCOVERY_BSP_VERSION_MAIN (0x02) /*!< [31:24] main version */
+#define __STM32F769I_DISCOVERY_BSP_VERSION_SUB1 (0x00) /*!< [23:16] sub1 version */
+#define __STM32F769I_DISCOVERY_BSP_VERSION_SUB2 (0x02) /*!< [15:8] sub2 version */
+#define __STM32F769I_DISCOVERY_BSP_VERSION_RC (0x00) /*!< [7:0] release candidate */
+#define __STM32F769I_DISCOVERY_BSP_VERSION ((__STM32F769I_DISCOVERY_BSP_VERSION_MAIN << 24)\
+ |(__STM32F769I_DISCOVERY_BSP_VERSION_SUB1 << 16)\
+ |(__STM32F769I_DISCOVERY_BSP_VERSION_SUB2 << 8 )\
+ |(__STM32F769I_DISCOVERY_BSP_VERSION_RC))
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_Macros LOW_LEVEL Private Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_Variables LOW_LEVEL Private Variables
+ * @{
+ */
+uint32_t GPIO_PIN[BSP_LEDn] = {BSP_LED1_PIN,
+ BSP_LED2_PIN};
+
+GPIO_TypeDef* GPIO_PORT[BSP_LEDn] = {BSP_LED1_GPIO_PORT,
+ BSP_LED2_GPIO_PORT};
+
+GPIO_TypeDef* BUTTON_PORT[BUTTONn] = {WAKEUP_BUTTON_GPIO_PORT };
+
+const uint16_t BUTTON_PIN[BUTTONn] = {WAKEUP_BUTTON_PIN };
+
+const uint16_t BUTTON_IRQn[BUTTONn] = {WAKEUP_BUTTON_EXTI_IRQn };
+
+
+static I2C_HandleTypeDef hI2cAudioHandler = {0};
+static I2C_HandleTypeDef hI2cExtHandler = {0};
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_FunctionPrototypes LOW_LEVEL Private FunctionPrototypes
+ * @{
+ */
+static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler);
+static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler);
+
+static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length);
+static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddSize, uint8_t *Buffer, uint16_t Length);
+static HAL_StatusTypeDef I2Cx_IsDeviceReady(I2C_HandleTypeDef *i2c_handler, uint16_t DevAddress, uint32_t Trials);
+static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr);
+
+/* AUDIO IO functions */
+void AUDIO_IO_Init(void);
+void AUDIO_IO_DeInit(void);
+void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value);
+uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg);
+void AUDIO_IO_Delay(uint32_t Delay);
+
+/* HDMI IO functions */
+void HDMI_IO_Init(void);
+void HDMI_IO_Delay(uint32_t Delay);
+void HDMI_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value);
+uint8_t HDMI_IO_Read(uint8_t Addr, uint8_t Reg);
+
+/* I2C EEPROM IO function */
+void EEPROM_IO_Init(void);
+HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize);
+HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize);
+HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials);
+
+/* TouchScreen (TS) IO functions */
+void TS_IO_Init(void);
+void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value);
+uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg);
+uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length);
+void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length);
+void TS_IO_Delay(uint32_t Delay);
+
+/* LCD Display IO functions */
+void OTM8009A_IO_Delay(uint32_t Delay);
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_BSP_Public_Functions BSP Public Functions
+ * @{
+ */
+
+ /**
+ * @brief This method returns the STM32F769I Discovery BSP Driver revision
+ * @retval version: 0xXYZR (8bits for each decimal, R for RC)
+ */
+uint32_t BSP_GetVersion(void)
+{
+ return __STM32F769I_DISCOVERY_BSP_VERSION;
+}
+
+/**
+ * @brief Configures LED GPIO.
+ * @param Led: LED to be configured.
+ * This parameter can be one of the following values:
+ * @arg LED1
+ * @arg LED2
+ * @retval None
+ */
+void BSP_LED_Init(Led_TypeDef Led)
+{
+ GPIO_InitTypeDef gpio_init_structure;
+
+ BSP_LEDx_GPIO_CLK_ENABLE();
+ /* Configure the GPIO_LED pin */
+ gpio_init_structure.Pin = GPIO_PIN[Led];
+ gpio_init_structure.Mode = GPIO_MODE_OUTPUT_PP;
+ gpio_init_structure.Pull = GPIO_PULLUP;
+ gpio_init_structure.Speed = GPIO_SPEED_HIGH;
+
+ HAL_GPIO_Init(GPIO_PORT[Led], &gpio_init_structure);
+
+}
+
+
+/**
+ * @brief DeInit LEDs.
+ * @param Led: LED to be configured.
+ * This parameter can be one of the following values:
+ * @arg LED1
+ * @arg LED2
+ * @note Led DeInit does not disable the GPIO clock
+ * @retval None
+ */
+void BSP_LED_DeInit(Led_TypeDef Led)
+{
+ GPIO_InitTypeDef gpio_init_structure;
+
+ /* DeInit the GPIO_LED pin */
+ gpio_init_structure.Pin = GPIO_PIN[Led];
+
+ /* Turn off LED */
+ HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET);
+ HAL_GPIO_DeInit(GPIO_PORT[Led], gpio_init_structure.Pin);
+}
+
+/**
+ * @brief Turns selected LED On.
+ * @param Led: LED to be set on
+ * This parameter can be one of the following values:
+ * @arg LED1
+ * @arg LED2
+ * @retval None
+ */
+void BSP_LED_On(Led_TypeDef Led)
+{
+ HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_SET);
+}
+
+/**
+ * @brief Turns selected LED Off.
+ * @param Led: LED to be set off
+ * This parameter can be one of the following values:
+ * @arg LED1
+ * @arg LED2
+ * @retval None
+ */
+void BSP_LED_Off(Led_TypeDef Led)
+{
+ HAL_GPIO_WritePin(GPIO_PORT[Led], GPIO_PIN[Led], GPIO_PIN_RESET);
+}
+
+/**
+ * @brief Toggles the selected LED.
+ * @param Led: LED to be toggled
+ * This parameter can be one of the following values:
+ * @arg LED1
+ * @arg LED2
+ * @retval None
+ */
+void BSP_LED_Toggle(Led_TypeDef Led)
+{
+ HAL_GPIO_TogglePin(GPIO_PORT[Led], GPIO_PIN[Led]);
+}
+
+/**
+ * @brief Configures button GPIO and EXTI Line.
+ * @param Button: Button to be configured
+ * This parameter can be one of the following values:
+ * @arg BUTTON_WAKEUP: Wakeup Push Button
+ * @arg BUTTON_USER: User Push Button
+ * @param Button_Mode: Button mode
+ * This parameter can be one of the following values:
+ * @arg BUTTON_MODE_GPIO: Button will be used as simple IO
+ * @arg BUTTON_MODE_EXTI: Button will be connected to EXTI line
+ * with interrupt generation capability
+ * @retval None
+ */
+void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode)
+{
+ GPIO_InitTypeDef gpio_init_structure;
+
+ /* Enable the BUTTON clock */
+ BUTTON_GPIO_CLK_ENABLE();
+
+ if(Button_Mode == BUTTON_MODE_GPIO)
+ {
+ /* Configure Button pin as input */
+ gpio_init_structure.Pin = BUTTON_PIN[Button];
+ gpio_init_structure.Mode = GPIO_MODE_INPUT;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_FAST;
+ HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure);
+ }
+
+ if(Button_Mode == BUTTON_MODE_EXTI)
+ {
+ /* Configure Button pin as input with External interrupt */
+ gpio_init_structure.Pin = BUTTON_PIN[Button];
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_FAST;
+
+ gpio_init_structure.Mode = GPIO_MODE_IT_RISING;
+
+ HAL_GPIO_Init(BUTTON_PORT[Button], &gpio_init_structure);
+
+ /* Enable and set Button EXTI Interrupt to the lowest priority */
+ HAL_NVIC_SetPriority((IRQn_Type)(BUTTON_IRQn[Button]), 0x0F, 0x00);
+ HAL_NVIC_EnableIRQ((IRQn_Type)(BUTTON_IRQn[Button]));
+ }
+}
+
+/**
+ * @brief Push Button DeInit.
+ * @param Button: Button to be configured
+ * This parameter can be one of the following values:
+ * @arg BUTTON_WAKEUP: Wakeup Push Button
+ * @arg BUTTON_USER: User Push Button
+ * @note PB DeInit does not disable the GPIO clock
+ * @retval None
+ */
+void BSP_PB_DeInit(Button_TypeDef Button)
+{
+ GPIO_InitTypeDef gpio_init_structure;
+
+ gpio_init_structure.Pin = BUTTON_PIN[Button];
+ HAL_NVIC_DisableIRQ((IRQn_Type)(BUTTON_IRQn[Button]));
+ HAL_GPIO_DeInit(BUTTON_PORT[Button], gpio_init_structure.Pin);
+}
+
+
+/**
+ * @brief Returns the selected button state.
+ * @param Button: Button to be checked
+ * This parameter can be one of the following values:
+ * @arg BUTTON_WAKEUP: Wakeup Push Button
+ * @arg BUTTON_USER: User Push Button
+ * @retval The Button GPIO pin value
+ */
+uint32_t BSP_PB_GetState(Button_TypeDef Button)
+{
+ return HAL_GPIO_ReadPin(BUTTON_PORT[Button], BUTTON_PIN[Button]);
+}
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Private_Functions STM32F769I_DISCOVERY_LOW_LEVEL Private Functions
+ * @{
+ */
+
+
+/*******************************************************************************
+ BUS OPERATIONS
+*******************************************************************************/
+
+/******************************* I2C Routines *********************************/
+/**
+ * @brief Initializes I2C MSP.
+ * @param i2c_handler : I2C handler
+ * @retval None
+ */
+static void I2Cx_MspInit(I2C_HandleTypeDef *i2c_handler)
+{
+ GPIO_InitTypeDef gpio_init_structure;
+
+ if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler))
+ {
+ /*** Configure the GPIOs ***/
+ /* Enable GPIO clock */
+ DISCOVERY_AUDIO_I2Cx_SCL_GPIO_CLK_ENABLE();
+ DISCOVERY_AUDIO_I2Cx_SDA_GPIO_CLK_ENABLE();
+ /* Configure I2C Tx as alternate function */
+ gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SCL_PIN;
+ gpio_init_structure.Mode = GPIO_MODE_AF_OD;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_FAST;
+ gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SCL_AF;
+ HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SCL_GPIO_PORT, &gpio_init_structure);
+
+ /* Configure I2C Rx as alternate function */
+ gpio_init_structure.Pin = DISCOVERY_AUDIO_I2Cx_SDA_PIN;
+ gpio_init_structure.Alternate = DISCOVERY_AUDIO_I2Cx_SDA_AF;
+ HAL_GPIO_Init(DISCOVERY_AUDIO_I2Cx_SDA_GPIO_PORT, &gpio_init_structure);
+
+ /*** Configure the I2C peripheral ***/
+ /* Enable I2C clock */
+ DISCOVERY_AUDIO_I2Cx_CLK_ENABLE();
+
+ /* Force the I2C peripheral clock reset */
+ DISCOVERY_AUDIO_I2Cx_FORCE_RESET();
+
+ /* Release the I2C peripheral clock reset */
+ DISCOVERY_AUDIO_I2Cx_RELEASE_RESET();
+
+ /* Enable and set I2C1 Interrupt to a lower priority */
+ HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_EV_IRQn, 0x0F, 0);
+ HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_EV_IRQn);
+
+ /* Enable and set I2C1 Interrupt to a lower priority */
+ HAL_NVIC_SetPriority(DISCOVERY_AUDIO_I2Cx_ER_IRQn, 0x0F, 0);
+ HAL_NVIC_EnableIRQ(DISCOVERY_AUDIO_I2Cx_ER_IRQn);
+
+ }
+ else
+ {
+ /*** Configure the GPIOs ***/
+ /* Enable GPIO clock */
+ DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE();
+
+ /* Configure I2C Tx as alternate function */
+ gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SCL_PIN;
+ gpio_init_structure.Mode = GPIO_MODE_AF_OD;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_FAST;
+ gpio_init_structure.Alternate = DISCOVERY_EXT_I2Cx_SCL_SDA_AF;
+ HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure);
+
+ /* Configure I2C Rx as alternate function */
+ gpio_init_structure.Pin = DISCOVERY_EXT_I2Cx_SDA_PIN;
+ HAL_GPIO_Init(DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT, &gpio_init_structure);
+
+ /*** Configure the I2C peripheral ***/
+ /* Enable I2C clock */
+ DISCOVERY_EXT_I2Cx_CLK_ENABLE();
+
+ /* Force the I2C peripheral clock reset */
+ DISCOVERY_EXT_I2Cx_FORCE_RESET();
+
+ /* Release the I2C peripheral clock reset */
+ DISCOVERY_EXT_I2Cx_RELEASE_RESET();
+
+ /* Enable and set I2C1 Interrupt to a lower priority */
+ HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_EV_IRQn, 0x0F, 0);
+ HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_EV_IRQn);
+
+ /* Enable and set I2C1 Interrupt to a lower priority */
+ HAL_NVIC_SetPriority(DISCOVERY_EXT_I2Cx_ER_IRQn, 0x0F, 0);
+ HAL_NVIC_EnableIRQ(DISCOVERY_EXT_I2Cx_ER_IRQn);
+ }
+}
+
+/**
+ * @brief Initializes I2C HAL.
+ * @param i2c_handler : I2C handler
+ * @retval None
+ */
+static void I2Cx_Init(I2C_HandleTypeDef *i2c_handler)
+{
+ if(HAL_I2C_GetState(i2c_handler) == HAL_I2C_STATE_RESET)
+ {
+ if (i2c_handler == (I2C_HandleTypeDef*)(&hI2cAudioHandler))
+ {
+ /* Audio and LCD I2C configuration */
+ i2c_handler->Instance = DISCOVERY_AUDIO_I2Cx;
+ }
+ else
+ {
+ /* External, camera and Arduino connector I2C configuration */
+ i2c_handler->Instance = DISCOVERY_EXT_I2Cx;
+ }
+ i2c_handler->Init.Timing = DISCOVERY_I2Cx_TIMING;
+ i2c_handler->Init.OwnAddress1 = 0;
+ i2c_handler->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
+ i2c_handler->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
+ i2c_handler->Init.OwnAddress2 = 0;
+ i2c_handler->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
+ i2c_handler->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
+
+ /* Init the I2C */
+ I2Cx_MspInit(i2c_handler);
+ HAL_I2C_Init(i2c_handler);
+ }
+}
+
+/**
+ * @brief Reads multiple data.
+ * @param i2c_handler : I2C handler
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @param MemAddress: memory address
+ * @param Buffer: Pointer to data buffer
+ * @param Length: Length of the data
+ * @retval HAL status
+ */
+static HAL_StatusTypeDef I2Cx_ReadMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length)
+{
+ HAL_StatusTypeDef status = HAL_OK;
+
+ status = HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000);
+
+ /* Check the communication status */
+ if(status != HAL_OK)
+ {
+ /* I2C error occured */
+ I2Cx_Error(i2c_handler, Addr);
+ }
+ return status;
+}
+
+
+/**
+ * @brief Writes a value in a register of the device through BUS in using DMA mode.
+ * @param i2c_handler : I2C handler
+ * @param Addr: Device address on BUS Bus.
+ * @param Reg: The target register address to write
+ * @param MemAddress: memory address
+ * @param Buffer: The target register value to be written
+ * @param Length: buffer size to be written
+ * @retval HAL status
+ */
+static HAL_StatusTypeDef I2Cx_WriteMultiple(I2C_HandleTypeDef *i2c_handler, uint8_t Addr, uint16_t Reg, uint16_t MemAddress, uint8_t *Buffer, uint16_t Length)
+{
+ HAL_StatusTypeDef status = HAL_OK;
+
+ status = HAL_I2C_Mem_Write(i2c_handler, Addr, (uint16_t)Reg, MemAddress, Buffer, Length, 1000);
+
+ /* Check the communication status */
+ if(status != HAL_OK)
+ {
+ /* Re-Initiaize the I2C Bus */
+ I2Cx_Error(i2c_handler, Addr);
+ }
+ return status;
+}
+
+/**
+ * @brief Checks if target device is ready for communication.
+ * @note This function is used with Memory devices
+ * @param i2c_handler : I2C handler
+ * @param DevAddress: Target device address
+ * @param Trials: Number of trials
+ * @retval HAL status
+ */
+static HAL_StatusTypeDef I2Cx_IsDeviceReady(I2C_HandleTypeDef *i2c_handler, uint16_t DevAddress, uint32_t Trials)
+{
+ return (HAL_I2C_IsDeviceReady(i2c_handler, DevAddress, Trials, 1000));
+}
+
+/**
+ * @brief Manages error callback by re-initializing I2C.
+ * @param i2c_handler : I2C handler
+ * @param Addr: I2C Address
+ * @retval None
+ */
+static void I2Cx_Error(I2C_HandleTypeDef *i2c_handler, uint8_t Addr)
+{
+ /* De-initialize the I2C communication bus */
+ HAL_I2C_DeInit(i2c_handler);
+
+ /* Re-Initialize the I2C communication bus */
+ I2Cx_Init(i2c_handler);
+}
+
+/**
+ * @}
+ */
+
+/*******************************************************************************
+ LINK OPERATIONS
+*******************************************************************************/
+
+/********************************* LINK AUDIO *********************************/
+
+/**
+ * @brief Initializes Audio low level.
+ */
+void AUDIO_IO_Init(void)
+{
+ I2Cx_Init(&hI2cAudioHandler);
+}
+
+/**
+ * @brief DeInitializes Audio low level.
+ */
+void AUDIO_IO_DeInit(void)
+{
+
+}
+
+/**
+ * @brief Writes a single data.
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @param Value: Data to be written
+ * @retval None
+ */
+void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value)
+{
+ uint16_t tmp = Value;
+
+ Value = ((uint16_t)(tmp >> 8) & 0x00FF);
+
+ Value |= ((uint16_t)(tmp << 8)& 0xFF00);
+
+ I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT,(uint8_t*)&Value, 2);
+}
+
+/**
+ * @brief Reads a single data.
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @retval Data to be read
+ */
+uint16_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg)
+{
+ uint16_t read_value = 0, tmp = 0;
+
+ I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_16BIT, (uint8_t*)&read_value, 2);
+
+ tmp = ((uint16_t)(read_value >> 8) & 0x00FF);
+
+ tmp |= ((uint16_t)(read_value << 8)& 0xFF00);
+
+ read_value = tmp;
+
+ return read_value;
+}
+
+/**
+ * @brief AUDIO Codec delay
+ * @param Delay: Delay in ms
+ */
+void AUDIO_IO_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+/******************************** LINK I2C EEPROM *****************************/
+
+/**
+ * @brief Initializes peripherals used by the I2C EEPROM driver.
+ */
+void EEPROM_IO_Init(void)
+{
+ I2Cx_Init(&hI2cExtHandler);
+}
+
+/**
+ * @brief Write data to I2C EEPROM driver in using DMA channel.
+ * @param DevAddress: Target device address
+ * @param MemAddress: Internal memory address
+ * @param pBuffer: Pointer to data buffer
+ * @param BufferSize: Amount of data to be sent
+ * @retval HAL status
+ */
+HAL_StatusTypeDef EEPROM_IO_WriteData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)
+{
+ return (I2Cx_WriteMultiple(&hI2cExtHandler, DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize));
+}
+
+/**
+ * @brief Read data from I2C EEPROM driver in using DMA channel.
+ * @param DevAddress: Target device address
+ * @param MemAddress: Internal memory address
+ * @param pBuffer: Pointer to data buffer
+ * @param BufferSize: Amount of data to be read
+ * @retval HAL status
+ */
+HAL_StatusTypeDef EEPROM_IO_ReadData(uint16_t DevAddress, uint16_t MemAddress, uint8_t* pBuffer, uint32_t BufferSize)
+{
+ return (I2Cx_ReadMultiple(&hI2cExtHandler, DevAddress, MemAddress, I2C_MEMADD_SIZE_16BIT, pBuffer, BufferSize));
+}
+
+/**
+ * @brief Checks if target device is ready for communication.
+ * @note This function is used with Memory devices
+ * @param DevAddress: Target device address
+ * @param Trials: Number of trials
+ * @retval HAL status
+ */
+HAL_StatusTypeDef EEPROM_IO_IsDeviceReady(uint16_t DevAddress, uint32_t Trials)
+{
+ return (I2Cx_IsDeviceReady(&hI2cExtHandler, DevAddress, Trials));
+}
+
+/******************************** LINK TS (TouchScreen) ***********************/
+
+/**
+ * @brief Initializes Touchscreen low level.
+ * @retval None
+ */
+void TS_IO_Init(void)
+{
+ I2Cx_Init(&hI2cAudioHandler);
+}
+
+/**
+ * @brief Writes a single data.
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @param Value: Data to be written
+ * @retval None
+ */
+void TS_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value)
+{
+ I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT,(uint8_t*)&Value, 1);
+}
+
+/**
+ * @brief Reads a single data.
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @retval Data to be read
+ */
+uint8_t TS_IO_Read(uint8_t Addr, uint8_t Reg)
+{
+ uint8_t read_value = 0;
+
+ I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, Reg, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&read_value, 1);
+
+ return read_value;
+}
+
+/**
+ * @brief Reads multiple data with I2C communication
+ * channel from TouchScreen.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @param Buffer: Pointer to data buffer
+ * @param Length: Length of the data
+ * @retval Number of read data
+ */
+uint16_t TS_IO_ReadMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length)
+{
+ return I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length);
+}
+
+/**
+ * @brief Writes multiple data with I2C communication
+ * channel from MCU to TouchScreen.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @param Buffer: Pointer to data buffer
+ * @param Length: Length of the data
+ * @retval None
+ */
+void TS_IO_WriteMultiple(uint8_t Addr, uint8_t Reg, uint8_t *Buffer, uint16_t Length)
+{
+ I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length);
+}
+
+/**
+ * @brief Delay function used in TouchScreen low level driver.
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void TS_IO_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+/**************************** LINK OTM8009A (Display driver) ******************/
+/**
+ * @brief OTM8009A delay
+ * @param Delay: Delay in ms
+ */
+void OTM8009A_IO_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+
+/**************************** LINK ADV7533 DSI-HDMI (Display driver) **********/
+/**
+ * @brief Initializes HDMI IO low level.
+ * @retval None
+ */
+void HDMI_IO_Init(void)
+{
+ I2Cx_Init(&hI2cAudioHandler);
+}
+
+/**
+ * @brief HDMI writes single data.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @param Value: Data to be written
+ * @retval None
+ */
+void HDMI_IO_Write(uint8_t Addr, uint8_t Reg, uint8_t Value)
+{
+ I2Cx_WriteMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, &Value, 1);
+}
+
+/**
+ * @brief Reads single data with I2C communication
+ * channel from HDMI bridge.
+ * @param Addr: I2C address
+ * @param Reg: Register address
+ * @retval Read data
+ */
+uint8_t HDMI_IO_Read(uint8_t Addr, uint8_t Reg)
+{
+ uint8_t value = 0x00;
+
+ I2Cx_ReadMultiple(&hI2cAudioHandler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, &value, 1);
+
+ return value;
+}
+
+/**
+ * @brief HDMI delay
+ * @param Delay: Delay in ms
+ * @retval None
+ */
+void HDMI_IO_Delay(uint32_t Delay)
+{
+ HAL_Delay(Delay);
+}
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/BSP/stm32f769i_discovery.h b/BSP/stm32f769i_discovery.h
new file mode 100644
index 0000000..eca7826
--- /dev/null
+++ b/BSP/stm32f769i_discovery.h
@@ -0,0 +1,334 @@
+/**
+ ******************************************************************************
+ * @file stm32f769i_discovery.h
+ * @author MCD Application Team
+ * @brief This file contains definitions for STM32F769I-Discovery LEDs,
+ * push-buttons hardware resources.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2016 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F769I_DISCOVERY_H
+#define __STM32F769I_DISCOVERY_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+ /* Includes ------------------------------------------------------------------*/
+#include "stm32f7xx_hal.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32F769I_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL STM32F769I-Discovery LOW LEVEL
+ * @{
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Exported_Types STM32F769I Discovery Low Level Exported Types
+ * @{
+ */
+
+/**
+ * @brief Define for STM32F769I_DISCOVERY board
+ */
+#if !defined (USE_STM32F769I_DISCO)
+ #define USE_STM32F769I_DISCO
+#endif
+
+/** @brief Led_TypeDef
+ * STM32F769I_DISCOVERY board leds definitions.
+ */
+typedef enum
+{
+ BSP_LED1 = 0,
+ BSP_LED_RED = BSP_LED1,
+ BSP_LED2 = 1,
+ BSP_LED_GREEN = BSP_LED2
+} Led_TypeDef;
+
+/** @brief Button_TypeDef
+ * STM32F769I_DISCOVERY board Buttons definitions.
+ */
+typedef enum
+{
+ BUTTON_WAKEUP = 0,
+} Button_TypeDef;
+
+#define BUTTON_USER BUTTON_WAKEUP
+
+/** @brief ButtonMode_TypeDef
+ * STM32F769I_DISCOVERY board Buttons Modes definitions.
+ */
+typedef enum
+{
+ BUTTON_MODE_GPIO = 0,
+ BUTTON_MODE_EXTI = 1
+
+} ButtonMode_TypeDef;
+
+/** @addtogroup Exported_types
+ * @{
+ */
+typedef enum
+{
+ PB_SET = 0,
+ PB_RESET = !PB_SET
+} ButtonValue_TypeDef;
+
+
+/** @brief DISCO_Status_TypeDef
+ * STM32F769I_DISCO board Status return possible values.
+ */
+typedef enum
+{
+ DISCO_OK = 0,
+ DISCO_ERROR = 1
+
+} DISCO_Status_TypeDef;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Exported_Constants STM32F769I Discovery Low Level Exported Constants
+ * @{
+ */
+
+
+/** @addtogroup STM32F769I_DISCOVERY_LOW_LEVEL_LED STM32F769I Discovery Low Level Led
+ * @{
+ */
+/* Always four leds for all revisions of Discovery boards */
+#define BSP_LEDn ((uint8_t)2)
+
+
+/* 2 Leds are connected to MCU directly on PJ13 and PJ5 */
+#define BSP_LED1_GPIO_PORT ((GPIO_TypeDef*)GPIOJ)
+#define BSP_LED2_GPIO_PORT ((GPIO_TypeDef*)GPIOJ)
+
+#define BSP_LEDx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOJ_CLK_ENABLE()
+#define BSP_LEDx_GPIO_CLK_DISABLE() __HAL_RCC_GPIOJ_CLK_DISABLE()
+
+#define BSP_LED1_PIN ((uint32_t)GPIO_PIN_13)
+#define BSP_LED2_PIN ((uint32_t)GPIO_PIN_5)
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F769I_DISCOVERY_LOW_LEVEL_BUTTON STM32F769I Discovery Low Level Button
+ * @{
+ */
+/* Only one User/Wakeup button */
+#define BUTTONn ((uint8_t)1)
+
+/**
+ * @brief Wakeup push-button
+ */
+#define WAKEUP_BUTTON_PIN GPIO_PIN_0
+#define WAKEUP_BUTTON_GPIO_PORT GPIOA
+#define WAKEUP_BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
+#define WAKEUP_BUTTON_GPIO_CLK_DISABLE() __HAL_RCC_GPIOA_CLK_DISABLE()
+#define WAKEUP_BUTTON_EXTI_IRQn EXTI0_IRQn
+
+/* Define the USER button as an alias of the Wakeup button */
+#define USER_BUTTON_PIN WAKEUP_BUTTON_PIN
+#define USER_BUTTON_GPIO_PORT WAKEUP_BUTTON_GPIO_PORT
+#define USER_BUTTON_GPIO_CLK_ENABLE() WAKEUP_BUTTON_GPIO_CLK_ENABLE()
+#define USER_BUTTON_GPIO_CLK_DISABLE() WAKEUP_BUTTON_GPIO_CLK_DISABLE()
+#define USER_BUTTON_EXTI_IRQn WAKEUP_BUTTON_EXTI_IRQn
+
+#define BUTTON_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
+
+/**
+ * @}
+ */
+
+/**
+ * @brief USB OTG HS Over Current signal
+ */
+#define OTG_HS_OVER_CURRENT_PIN GPIO_PIN_4
+#define OTG_HS_OVER_CURRENT_PORT GPIOD
+#define OTG_HS_OVER_CURRENT_PORT_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
+
+/**
+ * @brief SD-detect signal
+ */
+#define SD_DETECT_PIN ((uint32_t)GPIO_PIN_15)
+#define SD_DETECT_GPIO_PORT ((GPIO_TypeDef*)GPIOI)
+#define SD_DETECT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
+#define SD_DETECT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE()
+#define SD_DETECT_EXTI_IRQn EXTI15_10_IRQn
+
+/**
+ * @brief Touch screen interrupt signal
+ */
+#define TS_INT_PIN ((uint32_t)GPIO_PIN_13)
+#define TS_INT_GPIO_PORT ((GPIO_TypeDef*)GPIOI)
+#define TS_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
+#define TS_INT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOI_CLK_DISABLE()
+#define TS_INT_EXTI_IRQn EXTI15_10_IRQn
+
+/**
+ * @brief TouchScreen FT6206 Slave I2C address 1
+ */
+#define TS_I2C_ADDRESS ((uint16_t)0x54)
+
+/**
+ * @brief TouchScreen FT6336G Slave I2C address 2
+ */
+#define TS_I2C_ADDRESS_A02 ((uint16_t)0x70)
+
+/**
+ * @brief LCD DSI Slave I2C address 1
+ */
+#define LCD_DSI_ADDRESS TS_I2C_ADDRESS
+
+/**
+ * @brief LCD DSI Slave I2C address 2
+ */
+#define LCD_DSI_ADDRESS_A02 TS_I2C_ADDRESS_A02
+
+/**
+ * @brief Audio I2C Slave address
+ */
+#define AUDIO_I2C_ADDRESS ((uint16_t)0x34)
+
+/**
+ * @brief EEPROM I2C Slave address 1
+ */
+#define EEPROM_I2C_ADDRESS_A01 ((uint16_t)0xA0)
+
+/**
+ * @brief EEPROM I2C Slave address 2
+ */
+#define EEPROM_I2C_ADDRESS_A02 ((uint16_t)0xA6)
+
+/**
+ * @brief User can use this section to tailor I2C4/I2C4 instance used and associated
+ * resources (audio codec).
+ * Definition for I2C4 clock resources
+ */
+#define DISCOVERY_AUDIO_I2Cx I2C4
+#define DISCOVERY_AUDIO_I2Cx_CLK_ENABLE() __HAL_RCC_I2C4_CLK_ENABLE()
+#define DISCOVERY_AUDIO_I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
+#define DISCOVERY_AUDIO_I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
+
+#define DISCOVERY_AUDIO_I2Cx_FORCE_RESET() __HAL_RCC_I2C4_FORCE_RESET()
+#define DISCOVERY_AUDIO_I2Cx_RELEASE_RESET() __HAL_RCC_I2C4_RELEASE_RESET()
+
+/** @brief Definition for I2C4 Pins
+ */
+#define DISCOVERY_AUDIO_I2Cx_SCL_PIN GPIO_PIN_12 /*!< PD12 */
+#define DISCOVERY_AUDIO_I2Cx_SCL_AF GPIO_AF4_I2C4
+#define DISCOVERY_AUDIO_I2Cx_SCL_GPIO_PORT GPIOD
+#define DISCOVERY_AUDIO_I2Cx_SDA_PIN GPIO_PIN_7 /*!< PB7 */
+#define DISCOVERY_AUDIO_I2Cx_SDA_AF GPIO_AF11_I2C4
+#define DISCOVERY_AUDIO_I2Cx_SDA_GPIO_PORT GPIOB
+/** @brief Definition of I2C4 interrupt requests
+ */
+#define DISCOVERY_AUDIO_I2Cx_EV_IRQn I2C4_EV_IRQn
+#define DISCOVERY_AUDIO_I2Cx_ER_IRQn I2C4_ER_IRQn
+
+/**
+ * @brief User can use this section to tailor I2C1/I2C1 instance used and associated
+ * resources.
+ * Definition for I2C1 clock resources
+ */
+#define DISCOVERY_EXT_I2Cx I2C1
+#define DISCOVERY_EXT_I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE()
+#define DISCOVERY_DMAx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE()
+#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
+
+#define DISCOVERY_EXT_I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET()
+#define DISCOVERY_EXT_I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET()
+
+/** @brief Definition for I2C1 Pins
+ */
+#define DISCOVERY_EXT_I2Cx_SCL_PIN GPIO_PIN_8 /*!< PB8 */
+#define DISCOVERY_EXT_I2Cx_SCL_SDA_GPIO_PORT GPIOB
+#define DISCOVERY_EXT_I2Cx_SCL_SDA_AF GPIO_AF4_I2C1
+#define DISCOVERY_EXT_I2Cx_SDA_PIN GPIO_PIN_9 /*!< PB9 */
+
+/** @brief Definition of I2C interrupt requests
+ */
+#define DISCOVERY_EXT_I2Cx_EV_IRQn I2C1_EV_IRQn
+#define DISCOVERY_EXT_I2Cx_ER_IRQn I2C1_ER_IRQn
+
+/* I2C TIMING Register define when I2C clock source is SYSCLK */
+/* I2C TIMING is calculated from APB1 source clock = 50 MHz */
+/* Due to the big MOFSET capacity for adapting the camera level the rising time is very large (>1us) */
+/* 0x40912732 takes in account the big rising and aims a clock of 100khz */
+#ifndef DISCOVERY_I2Cx_TIMING
+#define DISCOVERY_I2Cx_TIMING ((uint32_t)0x40912732)
+#endif /* DISCOVERY_I2Cx_TIMING */
+
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Exported_Macros STM32F769I Discovery Low Level Exported Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_LOW_LEVEL_Exported_Functions STM32F769I Discovery Low Level Exported Functions
+ * @{
+ */
+uint32_t BSP_GetVersion(void);
+void BSP_LED_Init(Led_TypeDef Led);
+void BSP_LED_DeInit(Led_TypeDef Led);
+void BSP_LED_On(Led_TypeDef Led);
+void BSP_LED_Off(Led_TypeDef Led);
+void BSP_LED_Toggle(Led_TypeDef Led);
+void BSP_PB_Init(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode);
+void BSP_PB_DeInit(Button_TypeDef Button);
+uint32_t BSP_PB_GetState(Button_TypeDef Button);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F769I_DISCOVERY_H */
+
diff --git a/BSP/stm32f769i_discovery_audio.c b/BSP/stm32f769i_discovery_audio.c
new file mode 100644
index 0000000..308edb5
--- /dev/null
+++ b/BSP/stm32f769i_discovery_audio.c
@@ -0,0 +1,2247 @@
+/**
+ ******************************************************************************
+ * @file stm32f769i_discovery_audio.c
+ * @author MCD Application Team
+ * @brief This file provides the Audio driver for the STM32F769I-DISCOVERY
+ * board.
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2016 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ @verbatim
+ How To use this driver:
+ -----------------------
+ + This driver supports STM32F7xx devices on STM32F769I-DISCOVERY (MB1225) Evaluation boards.
+ + Call the function BSP_AUDIO_OUT_Init(
+ OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER,
+ OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH)
+ Volume : Initial volume to be set (0 is min (mute), 100 is max (100%)
+ AudioFreq : Audio frequency in Hz (8000, 16000, 22500, 32000...)
+ this parameter is relative to the audio file/stream type.
+ )
+ This function configures all the hardware required for the audio application (codec, I2C, SAI,
+ GPIOs, DMA and interrupt if needed). This function returns AUDIO_OK if configuration is OK.
+ If the returned value is different from AUDIO_OK or the function is stuck then the communication with
+ the codec has failed (try to un-plug the power or reset device in this case).
+ - OUTPUT_DEVICE_SPEAKER : only speaker will be set as output for the audio stream.
+ - OUTPUT_DEVICE_HEADPHONE: only headphones will be set as output for the audio stream.
+ - OUTPUT_DEVICE_BOTH : both Speaker and Headphone are used as outputs for the audio stream
+ at the same time.
+ Note. On STM32F769I-DISCOVERY SAI_DMA is configured in CIRCULAR mode. Due to this the application
+ does NOT need to call BSP_AUDIO_OUT_ChangeBuffer() to assure streaming.
+ + Call the function BSP_AUDIO_OUT_Play(
+ pBuffer: pointer to the audio data file address
+ Size : size of the buffer to be sent in Bytes
+ )
+ to start playing (for the first time) from the audio file/stream.
+ + Call the function BSP_AUDIO_OUT_Pause() to pause playing
+ + Call the function BSP_AUDIO_OUT_Resume() to resume playing.
+ Note. After calling BSP_AUDIO_OUT_Pause() function for pause, only BSP_AUDIO_OUT_Resume() should be called
+ for resume (it is not allowed to call BSP_AUDIO_OUT_Play() in this case).
+ Note. This function should be called only when the audio file is played or paused (not stopped).
+ + For each mode, you may need to implement the relative callback functions into your code.
+ The Callback functions are named BSP_AUDIO_OUT_XXX_CallBack() and only their prototypes are declared in
+ the stm32f769i_discovery_audio.h file. (refer to the example for more details on the callbacks implementations)
+ + To Stop playing, to modify the volume level, the frequency, the audio frame slot,
+ the device output mode the mute or the stop, use the functions: BSP_AUDIO_OUT_SetVolume(),
+ AUDIO_OUT_SetFrequency(), BSP_AUDIO_OUT_SetAudioFrameSlot(), BSP_AUDIO_OUT_SetOutputMode(),
+ BSP_AUDIO_OUT_SetMute() and BSP_AUDIO_OUT_Stop().
+
+ + Call the function BSP_AUDIO_IN_Init(
+ AudioFreq: Audio frequency in Hz (8000, 16000, 22500, 32000...)
+ this parameter is relative to the audio file/stream type.
+ BitRes: Bit resolution fixed to 16bit
+ ChnlNbr: Number of channel to be configured for the DFSDM peripheral
+ )
+ This function configures all the hardware required for the audio in application (DFSDM filters and channels,
+ Clock source for DFSDM periphiral, GPIOs, DMA and interrupt if needed).
+ This function returns AUDIO_OK if configuration is OK.If the returned value is different from AUDIO_OK then
+ the configuration should be wrong.
+ Note: On STM32F769I-DISCOVERY, four DFSDM Channel/Filters are configured and their DMA streams are configured
+ in CIRCULAR mode.
+ + Call the function BSP_AUDIO_IN_AllocScratch(
+ pScratch: pointer to scratch tables
+ size: size of scratch buffer)
+ This function must be called before BSP_AUDIO_IN_RECORD() to allocate buffer scratch for each DFSDM channel
+ and its size.
+ Note: These buffers scratch are used as intermidiate buffers to collect data within final record buffer.
+ size is the total size of the four buffers scratch; If size is 512 then the size of each is 128.
+ This function must be called after BSP_AUDIO_IN_Init()
+ + Call the function BSP_AUDIO_IN_RECORD(
+ pBuf: pointer to the recorded audio data file address
+ Size: size of the buffer to be written in Bytes
+ )
+ to start recording from microphones.
+
+ + Call the function BSP_AUDIO_IN_Pause() to pause recording
+ + Call the function BSP_AUDIO_IN_Resume() to recording playing.
+ Note. After calling BSP_AUDIO_IN_Pause() function for pause, only BSP_AUDIO_IN_Resume() should be called
+ for resume (it is not allowed to call BSP_AUDIO_IN_RECORD() in this case).
+ + Call the function BSP_AUDIO_IN_Stop() to stop recording
+ + For each mode, you may need to implement the relative callback functions into your code.
+ The Callback functions are named BSP_AUDIO_IN_XXX_CallBack() and only their prototypes are declared in
+ the stm32f769i_discovery_audio.h file. (refer to the example for more details on the callbacks implementations)
+
+ Driver architecture:
+ --------------------
+ + This driver provides the High Audio Layer: consists of the function API exported in the stm32f769i_discovery_audio.h file
+ (BSP_AUDIO_OUT_Init(), BSP_AUDIO_OUT_Play() ...)
+ + This driver provide also the Media Access Layer (MAL): which consists of functions allowing to access the media containing/
+ providing the audio file/stream. These functions are also included as local functions into
+ the stm32f769i_discovery_audio.c file (DFSDMx_Init(), DFSDMx_DeInit(), SAIx_Init() and SAIx_DeInit())
+
+ Known Limitations:
+ ------------------
+ 1- If the TDM Format used to play in parallel 2 audio Stream (the first Stream is configured in codec SLOT0 and second
+ Stream in SLOT1) the Pause/Resume, volume and mute feature will control the both streams.
+ 2- Parsing of audio file is not implemented (in order to determine audio file properties: Mono/Stereo, Data size,
+ File size, Audio Frequency, Audio Data header size ...). The configuration is fixed for the given audio file.
+ 3- Supports only Stereo audio streaming.
+ 4- Supports only 16-bits audio data size.
+ @endverbatim
+ ******************************************************************************
+ */
+
+/* Dependencies
+- stm32f769i_discovery.c
+- stm32f7xx_hal_sai.c
+- stm32f7xx_hal_dfsdm.c
+- stm32f7xx_hal_dma.c
+- stm32f7xx_hal_gpio.c
+- stm32f7xx_hal_cortex.c
+- stm32f7xx_hal_rcc_ex.h
+- wm8994.c
+EndDependencies */
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32f769i_discovery_audio.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32F769I_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO STM32F769I_DISCOVERY AUDIO
+ * @brief This file includes the low layer driver for wm8994 Audio Codec
+ * available on STM32F769I-DISCOVERY discoveryuation board(MB1225).
+ * @{
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Types STM32F769I_DISCOVERY_AUDIO Private Types
+ * @{
+ */
+typedef struct
+{
+ uint16_t *pRecBuf; /* Pointer to record user buffer */
+ uint32_t RecSize; /* Size to record in mono, double size to record in stereo */
+}AUDIOIN_TypeDef;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Defines STM32F769I_DISCOVERY_AUDIO Private Defines
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Macros STM32F769I_DISCOVERY_AUDIO Private Macros
+ * @{
+ */
+/*### RECORD ###*/
+#define DFSDM_OVER_SAMPLING(__FREQUENCY__) \
+ (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 256 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 256 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 128 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 128 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 64 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 64 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 40 : 20 \
+
+#define DFSDM_CLOCK_DIVIDER(__FREQUENCY__) \
+ (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 24 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 4 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 24 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 4 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 24 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 4 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 25 : 25 \
+
+#define DFSDM_FILTER_ORDER(__FREQUENCY__) \
+ (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? DFSDM_FILTER_SINC4_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? DFSDM_FILTER_SINC3_ORDER \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? DFSDM_FILTER_SINC3_ORDER : DFSDM_FILTER_SINC5_ORDER \
+
+#define DFSDM_RIGHT_BIT_SHIFT(__FREQUENCY__) \
+ (__FREQUENCY__ == AUDIO_FREQUENCY_8K) ? 8 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_11K) ? 8 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_16K) ? 3 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_22K) ? 4 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_32K) ? 7 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_44K) ? 0 \
+ : (__FREQUENCY__ == AUDIO_FREQUENCY_48K) ? 0 : 4 \
+
+/* Saturate the record PCM sample */
+#define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N)))
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Variables STM32F769I_DISCOVERY_AUDIO Private Variables
+ * @{
+ */
+/* PLAY */
+AUDIO_DrvTypeDef *audio_drv;
+SAI_HandleTypeDef haudio_out_sai;
+SAI_HandleTypeDef haudio_in_sai;
+
+/* RECORD */
+AUDIOIN_TypeDef hAudioIn;
+
+DFSDM_Channel_HandleTypeDef hAudioInTopLeftChannel;
+DFSDM_Channel_HandleTypeDef hAudioInTopRightChannel;
+DFSDM_Filter_HandleTypeDef hAudioInTopLeftFilter;
+DFSDM_Filter_HandleTypeDef hAudioInTopRightFilter;
+DMA_HandleTypeDef hDmaTopLeft;
+DMA_HandleTypeDef hDmaTopRight;
+
+DFSDM_Channel_HandleTypeDef hAudioInButtomLeftChannel;
+DFSDM_Channel_HandleTypeDef hAudioInButtomRightChannel;
+DFSDM_Filter_HandleTypeDef hAudioInButtomLeftFilter;
+DFSDM_Filter_HandleTypeDef hAudioInButtomRightFilter;
+DMA_HandleTypeDef hDmaButtomLeft;
+DMA_HandleTypeDef hDmaButtomRight;
+
+/* Buffers for right and left samples */
+static int32_t *pScratchBuff[2*DEFAULT_AUDIO_IN_CHANNEL_NBR];
+static __IO int32_t ScratchSize;
+/* Cannel number to be used: 2 channels by default */
+static uint8_t AudioIn_ChannelNumber = DEFAULT_AUDIO_IN_CHANNEL_NBR;
+/* Input device to be used: digital microphones by default */
+static uint16_t AudioIn_Device = INPUT_DEVICE_DIGITAL_MIC;
+
+/* Buffers status flags */
+static uint32_t DmaTopLeftRecHalfCplt = 0;
+static uint32_t DmaTopLeftRecCplt = 0;
+static uint32_t DmaTopRightRecHalfCplt = 0;
+static uint32_t DmaTopRightRecCplt = 0;
+static uint32_t DmaButtomLeftRecHalfCplt = 0;
+static uint32_t DmaButtomLeftRecCplt = 0;
+static uint32_t DmaButtomRightRecHalfCplt = 0;
+static uint32_t DmaButtomRightRecCplt = 0;
+
+/* Application Buffer Trigger */
+static __IO uint32_t AppBuffTrigger = 0;
+static __IO uint32_t AppBuffHalf = 0;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_Private_Function_Prototypes STM32F769I_DISCOVERY_AUDIO Private Function Prototypes
+ * @{
+ */
+static void SAIx_Out_Init(uint32_t AudioFreq);
+static void SAIx_Out_DeInit(void);
+static void SAI_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params);
+static void SAI_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params);
+static void SAIx_In_Init(uint32_t AudioFreq);
+static void SAIx_In_DeInit(void);
+static void DFSDMx_ChannelMspInit(void);
+static void DFSDMx_FilterMspInit(void);
+static void DFSDMx_ChannelMspDeInit(void);
+static void DFSDMx_FilterMspDeInit(void);
+static uint8_t DFSDMx_Init(uint32_t AudioFreq);
+static uint8_t DFSDMx_DeInit(void);
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_out_Private_Functions STM32F769I_DISCOVERY_AUDIO_Out Private Functions
+ * @{
+ */
+
+/**
+ * @brief Configures the audio peripherals.
+ * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
+ * or OUTPUT_DEVICE_BOTH.
+ * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max))
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq)
+{
+ uint8_t ret = AUDIO_ERROR;
+ uint32_t deviceid = 0x00;
+
+ /* Disable SAI */
+ SAIx_Out_DeInit();
+
+ /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
+ BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL);
+
+ /* SAI data transfer preparation:
+ Prepare the Media to be used for the audio transfer from memory to SAI peripheral */
+ haudio_out_sai.Instance = AUDIO_OUT_SAIx;
+ if(HAL_SAI_GetState(&haudio_out_sai) == HAL_SAI_STATE_RESET)
+ {
+ /* Init the SAI MSP: this __weak function can be redefined by the application*/
+ BSP_AUDIO_OUT_MspInit(&haudio_out_sai, NULL);
+ }
+ SAIx_Out_Init(AudioFreq);
+
+ /* wm8994 codec initialization */
+ deviceid = wm8994_drv.ReadID(AUDIO_I2C_ADDRESS);
+
+ if((deviceid) == WM8994_ID)
+ {
+ /* Reset the Codec Registers */
+ wm8994_drv.Reset(AUDIO_I2C_ADDRESS);
+ /* Initialize the audio driver structure */
+ audio_drv = &wm8994_drv;
+ ret = AUDIO_OK;
+ }
+ else
+ {
+ ret = AUDIO_ERROR;
+ }
+
+ if(ret == AUDIO_OK)
+ {
+ /* Initialize the codec internal registers */
+ audio_drv->Init(AUDIO_I2C_ADDRESS, OutputDevice, Volume, AudioFreq);
+ }
+
+ return ret;
+}
+
+/**
+ * @brief Starts playing audio stream from a data buffer for a determined size.
+ * @param pBuffer: Pointer to the buffer
+ * @param Size: Number of audio data BYTES.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size)
+{
+ /* Call the audio Codec Play function */
+ if(audio_drv->Play(AUDIO_I2C_ADDRESS, (uint16_t *)pBuffer, Size) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ else
+ {
+ /* Update the Media layer and enable it for play */
+ HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, DMA_MAX(Size / AUDIODATA_SIZE));
+
+ return AUDIO_OK;
+ }
+}
+
+/**
+ * @brief Sends n-Bytes on the SAI interface.
+ * @param pData: pointer on data address
+ * @param Size: number of data to be written
+ * @retval None
+ */
+void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size)
+{
+ HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pData, Size);
+}
+
+/**
+ * @brief This function Pauses the audio file stream. In case
+ * of using DMA, the DMA Pause feature is used.
+ * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only
+ * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play()
+ * function for resume could lead to unexpected behaviour).
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_OUT_Pause(void)
+{
+ /* Call the Audio Codec Pause/Resume function */
+ if(audio_drv->Pause(AUDIO_I2C_ADDRESS) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ else
+ {
+ /* Call the Media layer pause function */
+ HAL_SAI_DMAPause(&haudio_out_sai);
+
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+ }
+}
+
+/**
+ * @brief Resumes the audio file stream.
+ * @note When calling BSP_AUDIO_OUT_Pause() function for pause, only
+ * BSP_AUDIO_OUT_Resume() function should be called for resume (use of BSP_AUDIO_OUT_Play()
+ * function for resume could lead to unexpected behaviour).
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_OUT_Resume(void)
+{
+ /* Call the Audio Codec Pause/Resume function */
+ if(audio_drv->Resume(AUDIO_I2C_ADDRESS) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ else
+ {
+ /* Call the Media layer pause/resume function */
+ HAL_SAI_DMAResume(&haudio_out_sai);
+
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+ }
+}
+
+/**
+ * @brief Stops audio playing and Power down the Audio Codec.
+ * @param Option: could be one of the following parameters
+ * - CODEC_PDWN_SW: for software power off (by writing registers).
+ * Then no need to reconfigure the Codec after power on.
+ * - CODEC_PDWN_HW: completely shut down the codec (physically).
+ * Then need to reconfigure the Codec after power on.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option)
+{
+ /* Call the Media layer stop function */
+ HAL_SAI_DMAStop(&haudio_out_sai);
+
+ /* Call Audio Codec Stop function */
+ if(audio_drv->Stop(AUDIO_I2C_ADDRESS, Option) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ else
+ {
+ if(Option == CODEC_PDWN_HW)
+ {
+ /* Wait at least 100us */
+ HAL_Delay(1);
+ }
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+ }
+}
+
+/**
+ * @brief Controls the current audio volume level.
+ * @param Volume: Volume level to be set in percentage from 0% to 100% (0 for
+ * Mute and 100 for Max volume level).
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume)
+{
+ /* Call the codec volume control function with converted volume value */
+ if(audio_drv->SetVolume(AUDIO_I2C_ADDRESS, Volume) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ else
+ {
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+ }
+}
+
+/**
+ * @brief Enables or disables the MUTE mode by software
+ * @param Cmd: Could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to
+ * unmute the codec and restore previous volume level.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd)
+{
+ /* Call the Codec Mute function */
+ if(audio_drv->SetMute(AUDIO_I2C_ADDRESS, Cmd) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ else
+ {
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+ }
+}
+
+/**
+ * @brief Switch dynamically (while audio file is played) the output target
+ * (speaker or headphone).
+ * @param Output: The audio output target: OUTPUT_DEVICE_SPEAKER,
+ * OUTPUT_DEVICE_HEADPHONE or OUTPUT_DEVICE_BOTH
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output)
+{
+ /* Call the Codec output device function */
+ if(audio_drv->SetOutputMode(AUDIO_I2C_ADDRESS, Output) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ else
+ {
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+ }
+}
+
+/**
+ * @brief Updates the audio frequency.
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
+ * audio frequency.
+ * @retval None
+ */
+void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq)
+{
+ /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
+ BSP_AUDIO_OUT_ClockConfig(&haudio_out_sai, AudioFreq, NULL);
+
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&haudio_out_sai);
+
+ /* Update the SAI audio frequency configuration */
+ haudio_out_sai.Init.AudioFrequency = AudioFreq;
+ HAL_SAI_Init(&haudio_out_sai);
+
+ /* Enable SAI peripheral to generate MCLK */
+ __HAL_SAI_ENABLE(&haudio_out_sai);
+}
+
+/**
+ * @brief Updates the Audio frame slot configuration.
+ * @param AudioFrameSlot: specifies the audio Frame slot
+ * @note This API should be called after the BSP_AUDIO_OUT_Init() to adjust the
+ * audio frame slot.
+ * @retval None
+ */
+void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot)
+{
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&haudio_out_sai);
+
+ /* Update the SAI audio frame slot configuration */
+ haudio_out_sai.SlotInit.SlotActive = AudioFrameSlot;
+ HAL_SAI_Init(&haudio_out_sai);
+
+ /* Enable SAI peripheral to generate MCLK */
+ __HAL_SAI_ENABLE(&haudio_out_sai);
+}
+
+/**
+ * @brief De-initializes the audio out peripheral.
+ * @retval None
+ */
+void BSP_AUDIO_OUT_DeInit(void)
+{
+ SAIx_Out_DeInit();
+ /* DeInit the SAI MSP : this __weak function can be rewritten by the application */
+ BSP_AUDIO_OUT_MspDeInit(&haudio_out_sai, NULL);
+}
+
+/**
+ * @brief Tx Transfer completed callbacks.
+ * @param hsai: SAI handle
+ * @retval None
+ */
+void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
+{
+ /* Manage the remaining file size and new address offset: This function
+ should be coded by user (its prototype is already declared in stm32f769i_discovery_audio.h) */
+ BSP_AUDIO_OUT_TransferComplete_CallBack();
+}
+
+/**
+ * @brief Tx Half Transfer completed callbacks.
+ * @param hsai: SAI handle
+ * @retval None
+ */
+void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
+{
+ /* Manage the remaining file size and new address offset: This function
+ should be coded by user (its prototype is already declared in stm32f769i_discovery_audio.h) */
+ BSP_AUDIO_OUT_HalfTransfer_CallBack();
+}
+
+/**
+ * @brief SAI error callbacks.
+ * @param hsai: SAI handle
+ * @retval None
+ */
+void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
+{
+ if(hsai->Instance == AUDIO_OUT_SAIx)
+ {
+ BSP_AUDIO_OUT_Error_CallBack();
+ }
+ else
+ {
+ BSP_AUDIO_IN_Error_CallBack();
+ }
+}
+
+/**
+ * @brief Manages the DMA full Transfer complete event.
+ * @retval None
+ */
+__weak void BSP_AUDIO_OUT_TransferComplete_CallBack(void)
+{
+}
+
+/**
+ * @brief Manages the DMA Half Transfer complete event.
+ * @retval None
+ */
+__weak void BSP_AUDIO_OUT_HalfTransfer_CallBack(void)
+{
+}
+
+/**
+ * @brief Manages the DMA FIFO error event.
+ * @retval None
+ */
+__weak void BSP_AUDIO_OUT_Error_CallBack(void)
+{
+}
+
+/**
+ * @brief Initializes BSP_AUDIO_OUT MSP.
+ * @param hsai: SAI handle
+ * @param Params
+ * @retval None
+ */
+__weak void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params)
+{
+ static DMA_HandleTypeDef hdma_sai_tx;
+ GPIO_InitTypeDef gpio_init_structure;
+
+ /* Enable SAI clock */
+ AUDIO_OUT_SAIx_CLK_ENABLE();
+
+
+ /* Enable GPIO clock */
+ AUDIO_OUT_SAIx_MCLK_ENABLE();
+ AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE();
+
+ /* CODEC_SAI pins configuration: FS, SCK, MCK and SD pins ------------------*/
+ gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SD_PIN;
+ gpio_init_structure.Mode = GPIO_MODE_AF_PP;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_HIGH;
+ gpio_init_structure.Alternate = AUDIO_OUT_SAIx_AF;
+ HAL_GPIO_Init(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, &gpio_init_structure);
+
+ gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN;
+ HAL_GPIO_Init(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, &gpio_init_structure);
+
+ /* Enable the DMA clock */
+ AUDIO_OUT_SAIx_DMAx_CLK_ENABLE();
+
+ if(hsai->Instance == AUDIO_OUT_SAIx)
+ {
+ /* Configure the hdma_saiTx handle parameters */
+ hdma_sai_tx.Init.Channel = AUDIO_OUT_SAIx_DMAx_CHANNEL;
+ hdma_sai_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
+ hdma_sai_tx.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_sai_tx.Init.MemInc = DMA_MINC_ENABLE;
+ hdma_sai_tx.Init.PeriphDataAlignment = AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE;
+ hdma_sai_tx.Init.MemDataAlignment = AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE;
+ hdma_sai_tx.Init.Mode = DMA_CIRCULAR;
+ hdma_sai_tx.Init.Priority = DMA_PRIORITY_HIGH;
+ hdma_sai_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
+ hdma_sai_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
+ hdma_sai_tx.Init.MemBurst = DMA_MBURST_SINGLE;
+ hdma_sai_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
+
+ hdma_sai_tx.Instance = AUDIO_OUT_SAIx_DMAx_STREAM;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hsai, hdmatx, hdma_sai_tx);
+
+ /* Deinitialize the Stream for new transfer */
+ HAL_DMA_DeInit(&hdma_sai_tx);
+
+ /* Configure the DMA Stream */
+ HAL_DMA_Init(&hdma_sai_tx);
+ }
+
+ /* SAI DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(AUDIO_OUT_SAIx_DMAx_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
+ HAL_NVIC_EnableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ);
+}
+
+/**
+ * @brief Initializes SAI Audio IN MSP.
+ * @param hsai: SAI handle
+ * @param Params
+ * @retval None
+ */
+static void SAI_AUDIO_IN_MspInit(SAI_HandleTypeDef *hsai, void *Params)
+{
+ static DMA_HandleTypeDef hdma_sai_rx;
+ GPIO_InitTypeDef gpio_init_structure;
+
+ /* Enable SAI clock */
+ AUDIO_IN_SAIx_CLK_ENABLE();
+
+ /* Enable SD GPIO clock */
+ AUDIO_IN_SAIx_SD_ENABLE();
+ /* CODEC_SAI pin configuration: SD pin */
+ gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN;
+ gpio_init_structure.Mode = GPIO_MODE_AF_PP;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_FAST;
+ gpio_init_structure.Alternate = AUDIO_IN_SAIx_AF;
+ HAL_GPIO_Init(AUDIO_IN_SAIx_SD_GPIO_PORT, &gpio_init_structure);
+
+ /* Enable Audio INT GPIO clock */
+ AUDIO_IN_INT_GPIO_ENABLE();
+ /* Audio INT pin configuration: input */
+ gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN;
+ gpio_init_structure.Mode = GPIO_MODE_INPUT;
+ gpio_init_structure.Pull = GPIO_NOPULL;
+ gpio_init_structure.Speed = GPIO_SPEED_FAST;
+ HAL_GPIO_Init(AUDIO_IN_INT_GPIO_PORT, &gpio_init_structure);
+
+ /* Enable the DMA clock */
+ AUDIO_IN_SAIx_DMAx_CLK_ENABLE();
+
+ if(hsai->Instance == AUDIO_IN_SAIx)
+ {
+ /* Configure the hdma_sai_rx handle parameters */
+ hdma_sai_rx.Init.Channel = AUDIO_IN_SAIx_DMAx_CHANNEL;
+ hdma_sai_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hdma_sai_rx.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_sai_rx.Init.MemInc = DMA_MINC_ENABLE;
+ hdma_sai_rx.Init.PeriphDataAlignment = AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE;
+ hdma_sai_rx.Init.MemDataAlignment = AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE;
+ hdma_sai_rx.Init.Mode = DMA_CIRCULAR;
+ hdma_sai_rx.Init.Priority = DMA_PRIORITY_HIGH;
+ hdma_sai_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+ hdma_sai_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
+ hdma_sai_rx.Init.MemBurst = DMA_MBURST_SINGLE;
+ hdma_sai_rx.Init.PeriphBurst = DMA_MBURST_SINGLE;
+
+ hdma_sai_rx.Instance = AUDIO_IN_SAIx_DMAx_STREAM;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(hsai, hdmarx, hdma_sai_rx);
+
+ /* Deinitialize the Stream for new transfer */
+ HAL_DMA_DeInit(&hdma_sai_rx);
+
+ /* Configure the DMA Stream */
+ HAL_DMA_Init(&hdma_sai_rx);
+ }
+
+ /* SAI DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(AUDIO_IN_SAIx_DMAx_IRQ, AUDIO_IN_IRQ_PREPRIO, 0);
+ HAL_NVIC_EnableIRQ(AUDIO_IN_SAIx_DMAx_IRQ);
+
+ /* Audio INT IRQ Channel configuration */
+ HAL_NVIC_SetPriority(AUDIO_IN_INT_IRQ, AUDIO_IN_IRQ_PREPRIO, 0);
+ HAL_NVIC_EnableIRQ(AUDIO_IN_INT_IRQ);
+}
+
+/**
+ * @brief De-Initializes SAI Audio IN MSP.
+ * @param hsai: SAI handle
+ * @param Params
+ * @retval None
+ */
+static void SAI_AUDIO_IN_MspDeInit(SAI_HandleTypeDef *hsai, void *Params)
+{
+ GPIO_InitTypeDef gpio_init_structure;
+
+ /* SAI DMA IRQ Channel deactivation */
+ HAL_NVIC_DisableIRQ(AUDIO_IN_SAIx_DMAx_IRQ);
+
+ if(hsai->Instance == AUDIO_IN_SAIx)
+ {
+ /* Deinitialize the DMA stream */
+ HAL_DMA_DeInit(hsai->hdmatx);
+ }
+
+ /* Disable SAI peripheral */
+ __HAL_SAI_DISABLE(hsai);
+
+ /* Deactivates CODEC_SAI pin SD by putting them in input mode */
+ gpio_init_structure.Pin = AUDIO_IN_SAIx_SD_PIN;
+ HAL_GPIO_DeInit(AUDIO_IN_SAIx_SD_GPIO_PORT, gpio_init_structure.Pin);
+
+ gpio_init_structure.Pin = AUDIO_IN_INT_GPIO_PIN;
+ HAL_GPIO_DeInit(AUDIO_IN_INT_GPIO_PORT, gpio_init_structure.Pin);
+
+ /* Disable SAI clock */
+ AUDIO_IN_SAIx_CLK_DISABLE();
+}
+
+/**
+ * @brief Deinitializes SAI MSP.
+ * @param hsai: SAI handle
+ * @param Params
+ * @retval None
+ */
+__weak void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params)
+{
+ GPIO_InitTypeDef gpio_init_structure;
+
+ /* SAI DMA IRQ Channel deactivation */
+ HAL_NVIC_DisableIRQ(AUDIO_OUT_SAIx_DMAx_IRQ);
+
+ if(hsai->Instance == AUDIO_OUT_SAIx)
+ {
+ /* Deinitialize the DMA stream */
+ HAL_DMA_DeInit(hsai->hdmatx);
+ }
+
+ /* Disable SAI peripheral */
+ __HAL_SAI_DISABLE(hsai);
+
+ /* Deactivates CODEC_SAI pins FS, SCK, MCK and SD by putting them in input mode */
+ gpio_init_structure.Pin = AUDIO_OUT_SAIx_FS_PIN | AUDIO_OUT_SAIx_SCK_PIN | AUDIO_OUT_SAIx_SD_PIN;
+ HAL_GPIO_DeInit(AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT, gpio_init_structure.Pin);
+
+ gpio_init_structure.Pin = AUDIO_OUT_SAIx_MCLK_PIN;
+ HAL_GPIO_DeInit(AUDIO_OUT_SAIx_MCLK_GPIO_PORT, gpio_init_structure.Pin);
+
+ /* Disable SAI clock */
+ AUDIO_OUT_SAIx_CLK_DISABLE();
+
+ /* GPIO pins clock and DMA clock can be shut down in the applic
+ by surcharging this __weak function */
+}
+
+/**
+ * @brief Clock Config.
+ * @param hsai: might be required to set audio peripheral predivider if any.
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @param Params
+ * @note This API is called by BSP_AUDIO_OUT_Init() and BSP_AUDIO_OUT_SetFrequency()
+ * Being __weak it can be overwritten by the application
+ * @retval None
+ */
+__weak void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params)
+{
+ RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct;
+
+ HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct);
+
+ /* Set the PLL configuration according to the audio frequency */
+ if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K))
+ {
+ /* Configure PLLSAI prescalers */
+ /* PLLSAI_VCO: VCO_429M
+ SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 429/2 = 214.5 Mhz
+ SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 214.5/19 = 11.289 Mhz */
+ rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
+ rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLI2S;
+ rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429;
+ rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2;
+ rcc_ex_clk_init_struct.PLLI2SDivQ = 19;
+
+ HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct);
+
+ }
+ else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */
+ {
+ /* SAI clock config
+ PLLSAI_VCO: VCO_344M
+ SAI_CLK(first level) = PLLSAI_VCO/PLLSAIQ = 344/7 = 49.142 Mhz
+ SAI_CLK_x = SAI_CLK(first level)/PLLSAIDIVQ = 49.142/1 = 49.142 Mhz */
+ rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI1;
+ rcc_ex_clk_init_struct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLI2S;
+ rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344;
+ rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7;
+ rcc_ex_clk_init_struct.PLLI2SDivQ = 1;
+
+ HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct);
+ }
+}
+
+/*******************************************************************************
+ Static Functions
+*******************************************************************************/
+
+/**
+ * @brief Initializes the Audio Codec audio interface (SAI).
+ * @param AudioFreq: Audio frequency to be configured for the SAI peripheral.
+ * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123
+ * and user can update this configuration using
+ * @retval None
+ */
+static void SAIx_Out_Init(uint32_t AudioFreq)
+{
+ /* Initialize the haudio_out_sai Instance parameter */
+ haudio_out_sai.Instance = AUDIO_OUT_SAIx;
+
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&haudio_out_sai);
+
+ /* Configure SAI_Block_x
+ LSBFirst: Disabled
+ DataSize: 16 */
+ haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE;
+ haudio_out_sai.Init.AudioFrequency = AudioFreq;
+ haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_TX;
+ haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLED;
+ haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL;
+ haudio_out_sai.Init.DataSize = SAI_DATASIZE_16;
+ haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB;
+ haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE;
+ haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS;
+ haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLED;
+ haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
+ haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
+ haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING;
+ haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED;
+ haudio_out_sai.Init.Mckdiv = 0;
+
+ /* Configure SAI_Block_x Frame
+ Frame Length: 64
+ Frame active Length: 32
+ FS Definition: Start frame + Channel Side identification
+ FS Polarity: FS active Low
+ FS Offset: FS asserted one bit before the first bit of slot 0 */
+ haudio_out_sai.FrameInit.FrameLength = 128;
+ haudio_out_sai.FrameInit.ActiveFrameLength = 64;
+ haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
+ haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
+ haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
+
+ /* Configure SAI Block_x Slot
+ Slot First Bit Offset: 0
+ Slot Size : 16
+ Slot Number: 4
+ Slot Active: All slot actives */
+ haudio_out_sai.SlotInit.FirstBitOffset = 0;
+ haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
+ haudio_out_sai.SlotInit.SlotNumber = 4;
+ haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_0123;
+
+ HAL_SAI_Init(&haudio_out_sai);
+
+ /* Enable SAI peripheral to generate MCLK */
+ __HAL_SAI_ENABLE(&haudio_out_sai);
+}
+
+/**
+ * @brief Deinitializes the Audio Codec audio interface (SAI).
+ * @retval None
+ */
+static void SAIx_Out_DeInit(void)
+{
+ /* Initialize the haudio_out_sai Instance parameter */
+ haudio_out_sai.Instance = AUDIO_OUT_SAIx;
+
+ /* Disable SAI peripheral */
+ __HAL_SAI_DISABLE(&haudio_out_sai);
+
+ HAL_SAI_DeInit(&haudio_out_sai);
+}
+
+/**
+ * @brief Initializes the Audio Codec audio interface (SAI).
+ * @param AudioFreq: Audio frequency to be configured for the SAI peripheral.
+ * @note The default SlotActive configuration is set to CODEC_AUDIOFRAME_SLOT_0123
+ * and user can update this configuration using
+ * @retval None
+ */
+static void SAIx_In_Init(uint32_t AudioFreq)
+{
+ /* Initialize SAI1 block A in MASTER TX */
+ /* Initialize the haudio_out_sai Instance parameter */
+ haudio_out_sai.Instance = AUDIO_OUT_SAIx;
+
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&haudio_out_sai);
+
+ /* Configure SAI_Block_x
+ LSBFirst: Disabled
+ DataSize: 16 */
+ haudio_out_sai.Init.MonoStereoMode = SAI_STEREOMODE;
+ haudio_out_sai.Init.AudioFrequency = AudioFreq;
+ haudio_out_sai.Init.AudioMode = SAI_MODEMASTER_RX;
+ haudio_out_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
+ haudio_out_sai.Init.Protocol = SAI_FREE_PROTOCOL;
+ haudio_out_sai.Init.DataSize = SAI_DATASIZE_16;
+ haudio_out_sai.Init.FirstBit = SAI_FIRSTBIT_MSB;
+ haudio_out_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_FALLINGEDGE;
+ haudio_out_sai.Init.Synchro = SAI_ASYNCHRONOUS;
+ haudio_out_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE;
+ haudio_out_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
+ haudio_out_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
+ haudio_out_sai.Init.CompandingMode = SAI_NOCOMPANDING;
+ haudio_out_sai.Init.TriState = SAI_OUTPUT_NOTRELEASED;
+ haudio_out_sai.Init.Mckdiv = 0;
+
+ /* Configure SAI_Block_x Frame
+ Frame Length: 64
+ Frame active Length: 32
+ FS Definition: Start frame + Channel Side identification
+ FS Polarity: FS active Low
+ FS Offset: FS asserted one bit before the first bit of slot 0 */
+ haudio_out_sai.FrameInit.FrameLength = 64;
+ haudio_out_sai.FrameInit.ActiveFrameLength = 32;
+ haudio_out_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
+ haudio_out_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
+ haudio_out_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
+
+ /* Configure SAI Block_x Slot
+ Slot First Bit Offset: 0
+ Slot Size : 16
+ Slot Number: 4
+ Slot Active: All slot actives */
+ haudio_out_sai.SlotInit.FirstBitOffset = 0;
+ haudio_out_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
+ haudio_out_sai.SlotInit.SlotNumber = 4;
+ haudio_out_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_02;
+
+ HAL_SAI_Init(&haudio_out_sai);
+
+ /* Initialize SAI1 block B in SLAVE RX synchronous from SAI1 block A */
+ /* Initialize the haudio_in_sai Instance parameter */
+ haudio_in_sai.Instance = AUDIO_IN_SAIx;
+
+ /* Disable SAI peripheral to allow access to SAI internal registers */
+ __HAL_SAI_DISABLE(&haudio_in_sai);
+
+ /* Configure SAI_Block_x
+ LSBFirst: Disabled
+ DataSize: 16 */
+ haudio_in_sai.Init.MonoStereoMode = SAI_STEREOMODE;
+ haudio_in_sai.Init.AudioFrequency = AudioFreq;
+ haudio_in_sai.Init.AudioMode = SAI_MODESLAVE_RX;
+ haudio_in_sai.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
+ haudio_in_sai.Init.Protocol = SAI_FREE_PROTOCOL;
+ haudio_in_sai.Init.DataSize = SAI_DATASIZE_16;
+ haudio_in_sai.Init.FirstBit = SAI_FIRSTBIT_MSB;
+ haudio_in_sai.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE;
+ haudio_in_sai.Init.Synchro = SAI_SYNCHRONOUS;
+ haudio_in_sai.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
+ haudio_in_sai.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF;
+ haudio_in_sai.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
+ haudio_in_sai.Init.CompandingMode = SAI_NOCOMPANDING;
+ haudio_in_sai.Init.TriState = SAI_OUTPUT_RELEASED;
+ haudio_in_sai.Init.Mckdiv = 0;
+
+ /* Configure SAI_Block_x Frame
+ Frame Length: 64
+ Frame active Length: 32
+ FS Definition: Start frame + Channel Side identification
+ FS Polarity: FS active Low
+ FS Offset: FS asserted one bit before the first bit of slot 0 */
+ haudio_in_sai.FrameInit.FrameLength = 64;
+ haudio_in_sai.FrameInit.ActiveFrameLength = 32;
+ haudio_in_sai.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION;
+ haudio_in_sai.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW;
+ haudio_in_sai.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT;
+
+ /* Configure SAI Block_x Slot
+ Slot First Bit Offset: 0
+ Slot Size : 16
+ Slot Number: 4
+ Slot Active: All slot active */
+ haudio_in_sai.SlotInit.FirstBitOffset = 0;
+ haudio_in_sai.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE;
+ haudio_in_sai.SlotInit.SlotNumber = 4;
+ haudio_in_sai.SlotInit.SlotActive = CODEC_AUDIOFRAME_SLOT_02;
+
+ HAL_SAI_Init(&haudio_in_sai);
+
+ /* Enable SAI peripheral */
+ __HAL_SAI_ENABLE(&haudio_in_sai);
+
+ /* Enable SAI peripheral to generate MCLK */
+ __HAL_SAI_ENABLE(&haudio_out_sai);
+}
+
+/**
+ * @brief Deinitializes the output Audio Codec audio interface (SAI).
+ * @retval None
+ */
+static void SAIx_In_DeInit(void)
+{
+ /* Initialize the haudio_in_sai Instance parameter */
+ haudio_in_sai.Instance = AUDIO_IN_SAIx;
+ haudio_out_sai.Instance = AUDIO_OUT_SAIx;
+ /* Disable SAI peripheral */
+ __HAL_SAI_DISABLE(&haudio_in_sai);
+
+ HAL_SAI_DeInit(&haudio_in_sai);
+ HAL_SAI_DeInit(&haudio_out_sai);
+}
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_In_Private_Functions STM32F769I_DISCOVERY_AUDIO_In Private Functions
+ * @{
+ */
+
+/**
+ * @brief Initialize wave recording.
+ * @param AudioFreq: Audio frequency to be configured for the DFSDM peripheral.
+ * @param BitRes: Audio frequency to be configured for the DFSDM peripheral.
+ * @param ChnlNbr: Audio frequency to be configured for the DFSDM peripheral.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
+{
+ return BSP_AUDIO_IN_InitEx(INPUT_DEVICE_DIGITAL_MIC, AudioFreq, BitRes, ChnlNbr);
+}
+
+/**
+ * @brief Initialize wave recording.
+ * @param InputDevice: INPUT_DEVICE_DIGITAL_MIC or INPUT_DEVICE_ANALOG_MIC.
+ * @param AudioFreq: Audio frequency to be configured.
+ * @param BitRes: Audio bit resolution to be configured..
+ * @param ChnlNbr: Number of channel to be configured.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr)
+{
+ uint8_t ret = AUDIO_ERROR;
+ AudioIn_Device = InputDevice;
+
+ if(InputDevice == INPUT_DEVICE_DIGITAL_MIC)
+ {
+ AudioIn_ChannelNumber = ChnlNbr;
+ /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
+ BSP_AUDIO_IN_ClockConfig(&hAudioInTopLeftFilter, AudioFreq, NULL);
+
+ /* Init the SAI MSP: this __weak function can be redefined by the application*/
+ BSP_AUDIO_IN_MspInit();
+
+ /* Initializes DFSDM peripheral */
+ DFSDMx_Init(AudioFreq);
+ ret = AUDIO_OK;
+ }
+ else
+ {
+ /* Disable SAI */
+ SAIx_In_DeInit();
+
+ /* PLL clock is set depending by the AudioFreq (44.1khz vs 48khz groups) */
+ BSP_AUDIO_OUT_ClockConfig(&haudio_in_sai, AudioFreq, NULL);
+
+ haudio_in_sai.Instance = AUDIO_IN_SAIx;
+ if(HAL_SAI_GetState(&haudio_in_sai) == HAL_SAI_STATE_RESET)
+ {
+ BSP_AUDIO_OUT_MspInit(&haudio_in_sai, NULL);
+ BSP_AUDIO_IN_MspInit();
+ }
+
+ SAIx_In_Init(AudioFreq);
+
+ if((wm8994_drv.ReadID(AUDIO_I2C_ADDRESS)) == WM8994_ID)
+ {
+ /* Reset the Codec Registers */
+ wm8994_drv.Reset(AUDIO_I2C_ADDRESS);
+ /* Initialize the audio driver structure */
+ audio_drv = &wm8994_drv;
+ ret = AUDIO_OK;
+ }
+ else
+ {
+ ret = AUDIO_ERROR;
+ }
+
+ if(ret == AUDIO_OK)
+ {
+ /* Initialize the codec internal registers */
+ audio_drv->Init(AUDIO_I2C_ADDRESS, InputDevice, 100, AudioFreq);
+ }
+ }
+
+ /* Return AUDIO_OK when all operations are correctly done */
+ return ret;
+}
+
+/**
+ * @brief Allocate channel buffer scratch
+ * @param pScratch : pointer to scratch tables.
+ * @param size of scratch buffer
+ */
+uint8_t BSP_AUDIO_IN_AllocScratch (int32_t *pScratch, uint32_t size)
+{
+ uint32_t idx;
+
+ ScratchSize = (size / AudioIn_ChannelNumber);
+
+ /* copy scratch pointers */
+ for (idx = 0; idx < AudioIn_ChannelNumber; idx++)
+ {
+ pScratchBuff[idx] = (int32_t *)(pScratch + (idx * ScratchSize));
+ }
+ /* Return AUDIO_OK */
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Return audio in channel number
+ * @retval Number of channel
+ */
+uint8_t BSP_AUDIO_IN_GetChannelNumber(void)
+{
+ return AudioIn_ChannelNumber;
+}
+
+/**
+ * @brief Start audio recording.
+ * @param pbuf: Main buffer pointer for the recorded data storing
+ * @param size: Current size of the recorded buffer
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_IN_Record(uint16_t* pbuf, uint32_t size)
+{
+ if (AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC)
+ {
+ hAudioIn.pRecBuf = pbuf;
+ hAudioIn.RecSize = size;
+ /* Reset Application Buffer Trigger */
+ AppBuffTrigger = 0;
+ AppBuffHalf = 0;
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /* Call the Media layer start function for buttom right channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInButtomRightFilter, pScratchBuff[2], ScratchSize))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Call the Media layer start function for buttom left channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInButtomLeftFilter, pScratchBuff[3], ScratchSize))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* Call the Media layer start function for top right channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInTopRightFilter, pScratchBuff[0], ScratchSize))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Call the Media layer start function for top left channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInTopLeftFilter, pScratchBuff[1], ScratchSize))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ else
+ {
+ /* Start the process receive DMA */
+ if(HAL_OK !=HAL_SAI_Receive_DMA(&haudio_in_sai, (uint8_t*)pbuf, size))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Stop audio recording.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_IN_Stop(void)
+{
+ if (AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC)
+ {
+ AppBuffTrigger = 0;
+ AppBuffHalf = 0;
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /* Call the Media layer stop function for buttom right channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInButtomRightFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Call the Media layer stop function for buttom left channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInButtomLeftFilter))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ /* Call the Media layer stop function for top right channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInTopRightFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Call the Media layer stop function for top left channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInTopLeftFilter))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ else
+ {
+ /* Call the Media layer stop function */
+ HAL_SAI_DMAStop(&haudio_in_sai);
+
+ /* Call Audio Codec Stop function */
+ if(audio_drv->Stop(AUDIO_I2C_ADDRESS, CODEC_PDWN_HW) != 0)
+ {
+ return AUDIO_ERROR;
+ }
+ else
+ {
+ /* Wait at least 100us */
+ HAL_Delay(1);
+
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+ }
+ }
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Pause the audio file stream.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_IN_Pause(void)
+{
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /* Call the Media layer stop function */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInButtomRightFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Call the Media layer stop function */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInButtomLeftFilter))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ /* Call the Media layer stop function */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInTopRightFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Call the Media layer stop function */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStop_DMA(&hAudioInTopLeftFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Resume the audio file stream.
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+uint8_t BSP_AUDIO_IN_Resume(void)
+{
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /* Call the Media layer start function for buttom right channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInButtomRightFilter, pScratchBuff[2], ScratchSize))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Call the Media layer start function for buttom left channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInButtomLeftFilter, pScratchBuff[3], ScratchSize))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ /* Call the Media layer start function for top right channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInTopRightFilter, pScratchBuff[0], ScratchSize))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Call the Media layer start function for top left channel */
+ if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&hAudioInTopLeftFilter, pScratchBuff[1], ScratchSize))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Return AUDIO_OK when all operations are correctly done */
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Deinit the audio IN peripherals.
+ * @retval None
+ */
+void BSP_AUDIO_IN_DeInit(void)
+{
+ BSP_AUDIO_IN_MspDeInit();
+
+ if(AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC)
+ {
+ DFSDMx_DeInit();
+ }
+ else
+ {
+ SAIx_In_DeInit();
+ }
+}
+
+/**
+ * @brief Regular conversion complete callback.
+ * @note In interrupt mode, user has to read conversion value in this function
+ using HAL_DFSDM_FilterGetRegularValue.
+ * @param hdfsdm_filter : DFSDM filter handle.
+ * @retval None
+ */
+void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
+{
+ uint32_t index = 0;
+
+ if(hdfsdm_filter == &hAudioInTopLeftFilter)
+ {
+ DmaTopLeftRecCplt = 1;
+ }
+ else if(hdfsdm_filter == &hAudioInTopRightFilter)
+ {
+ DmaTopRightRecCplt = 1;
+ }
+ else if(hdfsdm_filter == &hAudioInButtomLeftFilter)
+ {
+ DmaButtomLeftRecCplt = 1;
+ }
+ else
+ {
+ DmaButtomRightRecCplt = 1;
+ }
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ if((DmaTopLeftRecCplt == 1) && (DmaTopRightRecCplt == 1) && (DmaButtomLeftRecCplt == 1) && (DmaButtomRightRecCplt == 1))
+ {
+ for(index = (ScratchSize/2) ; index < ScratchSize; index++)
+ {
+ hAudioIn.pRecBuf[AppBuffTrigger] = (uint16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760));
+ hAudioIn.pRecBuf[AppBuffTrigger + 1] = (uint16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760));
+ hAudioIn.pRecBuf[AppBuffTrigger + 2] = (uint16_t)(SaturaLH((pScratchBuff[3][index] >> 8), -32760, 32760));
+ hAudioIn.pRecBuf[AppBuffTrigger + 3] = (uint16_t)(SaturaLH((pScratchBuff[2][index] >> 8), -32760, 32760));
+ AppBuffTrigger +=4;
+ }
+ DmaTopLeftRecCplt = 0;
+ DmaTopRightRecCplt = 0;
+ DmaButtomLeftRecCplt = 0;
+ DmaButtomRightRecCplt = 0;
+ }
+ }
+ else
+ {
+ if((DmaTopLeftRecCplt == 1) && (DmaTopRightRecCplt == 1))
+ {
+ for(index = (ScratchSize/2) ; index < ScratchSize; index++)
+ {
+ hAudioIn.pRecBuf[AppBuffTrigger] = (uint16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760));
+ hAudioIn.pRecBuf[AppBuffTrigger + 1] = (uint16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760));
+ AppBuffTrigger +=2;
+ }
+ DmaTopLeftRecCplt = 0;
+ DmaTopRightRecCplt = 0;
+ }
+ }
+
+ /* Call Half Transfer Complete callback */
+ if((AppBuffTrigger == hAudioIn.RecSize/2) && (AppBuffHalf == 0))
+ {
+ AppBuffHalf = 1;
+ BSP_AUDIO_IN_HalfTransfer_CallBack();
+ }
+ /* Call Transfer Complete callback */
+ if(AppBuffTrigger == hAudioIn.RecSize)
+ {
+ /* Reset Application Buffer Trigger */
+ AppBuffTrigger = 0;
+ AppBuffHalf = 0;
+ /* Call the record update function to get the next buffer to fill and its size (size is ignored) */
+ BSP_AUDIO_IN_TransferComplete_CallBack();
+ }
+}
+
+/**
+ * @brief Half regular conversion complete callback.
+ * @param hdfsdm_filter : DFSDM filter handle.
+ * @retval None
+ */
+void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter)
+{
+ uint32_t index = 0;
+
+ if(hdfsdm_filter == &hAudioInTopLeftFilter)
+ {
+ DmaTopLeftRecHalfCplt = 1;
+ }
+ else if(hdfsdm_filter == &hAudioInTopRightFilter)
+ {
+ DmaTopRightRecHalfCplt = 1;
+ }
+ else if(hdfsdm_filter == &hAudioInButtomLeftFilter)
+ {
+ DmaButtomLeftRecHalfCplt = 1;
+ }
+ else
+ {
+ DmaButtomRightRecHalfCplt = 1;
+ }
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ if((DmaTopLeftRecHalfCplt == 1) && (DmaTopRightRecHalfCplt == 1) && (DmaButtomLeftRecHalfCplt == 1) && (DmaButtomRightRecHalfCplt == 1))
+ {
+ for(index = 0 ; index < ScratchSize/2; index++)
+ {
+ hAudioIn.pRecBuf[AppBuffTrigger] = (uint16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760));
+ hAudioIn.pRecBuf[AppBuffTrigger + 1] = (uint16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760));
+ hAudioIn.pRecBuf[AppBuffTrigger + 2] = (uint16_t)(SaturaLH((pScratchBuff[3][index] >> 8), -32760, 32760));
+ hAudioIn.pRecBuf[AppBuffTrigger + 3] = (uint16_t)(SaturaLH((pScratchBuff[2][index] >> 8), -32760, 32760));
+ AppBuffTrigger +=4;
+ }
+ DmaTopLeftRecHalfCplt = 0;
+ DmaTopRightRecHalfCplt = 0;
+ DmaButtomLeftRecHalfCplt = 0;
+ DmaButtomRightRecHalfCplt = 0;
+ }
+ }
+ else
+ {
+ if((DmaTopLeftRecHalfCplt == 1) && (DmaTopRightRecHalfCplt == 1))
+ {
+ for(index = 0 ; index < ScratchSize/2; index++)
+ {
+ hAudioIn.pRecBuf[AppBuffTrigger] = (uint16_t)(SaturaLH((pScratchBuff[1][index] >> 8), -32760, 32760));
+ hAudioIn.pRecBuf[AppBuffTrigger + 1] = (uint16_t)(SaturaLH((pScratchBuff[0][index] >> 8), -32760, 32760));
+ AppBuffTrigger +=2;
+ }
+ DmaTopLeftRecHalfCplt = 0;
+ DmaTopRightRecHalfCplt = 0;
+ }
+ }
+
+ /* Call Half Transfer Complete callback */
+ if((AppBuffTrigger == hAudioIn.RecSize/2) && (AppBuffHalf == 0))
+ {
+ AppBuffHalf = 1;
+ BSP_AUDIO_IN_HalfTransfer_CallBack();
+ }
+ /* Call Transfer Complete callback */
+ if(AppBuffTrigger == hAudioIn.RecSize)
+ {
+ /* Reset Application Buffer Trigger */
+ AppBuffTrigger = 0;
+ AppBuffHalf = 0;
+ /* Call the record update function to get the next buffer to fill and its size (size is ignored) */
+ BSP_AUDIO_IN_TransferComplete_CallBack();
+ }
+}
+
+/**
+ * @brief Half reception complete callback.
+ * @param hsai : SAI handle.
+ * @retval None
+ */
+void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
+{
+ /* Manage the remaining file size and new address offset: This function
+ should be coded by user (its prototype is already declared in stm32769i_discovery_audio.h) */
+ BSP_AUDIO_IN_HalfTransfer_CallBack();
+}
+
+/**
+ * @brief Reception complete callback.
+ * @param hsai : SAI handle.
+ * @retval None
+ */
+void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
+{
+ /* Call the record update function to get the next buffer to fill and its size (size is ignored) */
+ BSP_AUDIO_IN_TransferComplete_CallBack();
+}
+
+/**
+ * @brief User callback when record buffer is filled.
+ * @retval None
+ */
+__weak void BSP_AUDIO_IN_TransferComplete_CallBack(void)
+{
+ /* This function should be implemented by the user application.
+ It is called into this driver when the current buffer is filled
+ to prepare the next buffer pointer and its size. */
+}
+
+/**
+ * @brief Manages the DMA Half Transfer complete event.
+ * @retval None
+ */
+__weak void BSP_AUDIO_IN_HalfTransfer_CallBack(void)
+{
+ /* This function should be implemented by the user application.
+ It is called into this driver when the current buffer is filled
+ to prepare the next buffer pointer and its size. */
+}
+
+/**
+ * @brief Audio IN Error callback function.
+ * @retval None
+ */
+__weak void BSP_AUDIO_IN_Error_CallBack(void)
+{
+ /* This function is called when an Interrupt due to transfer error on or peripheral
+ error occurs. */
+}
+
+/**
+ * @brief Initialize BSP_AUDIO_IN MSP.
+ * @retval None
+ */
+__weak void BSP_AUDIO_IN_MspInit(void)
+{
+ if (AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC)
+ {
+ /* MSP channels initialization */
+ DFSDMx_ChannelMspInit();
+ /* MSP filters initialization */
+ DFSDMx_FilterMspInit();
+ }
+ else
+ {
+ SAI_AUDIO_IN_MspInit(&haudio_in_sai, NULL);
+ }
+}
+
+/**
+ * @brief DeInitialize BSP_AUDIO_IN MSP.
+ * @retval None
+ */
+__weak void BSP_AUDIO_IN_MspDeInit(void)
+{
+ if (AudioIn_Device == INPUT_DEVICE_DIGITAL_MIC)
+ {
+ /* MSP channels initialization */
+ DFSDMx_ChannelMspDeInit();
+ /* MSP filters initialization */
+ DFSDMx_FilterMspDeInit();
+ }
+ else
+ {
+ SAI_AUDIO_IN_MspDeInit(&haudio_in_sai, NULL);
+ }
+}
+
+/**
+ * @brief Clock Config.
+ * @param hdfsdm_filter: might be required to set audio peripheral predivider if any.
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @param Params
+ * @note This API is called by BSP_AUDIO_IN_Init()
+ * Being __weak it can be overwritten by the application
+ * @retval None
+ */
+__weak void BSP_AUDIO_IN_ClockConfig(DFSDM_Filter_HandleTypeDef *hdfsdm_filter, uint32_t AudioFreq, void *Params)
+{
+ RCC_PeriphCLKInitTypeDef rcc_ex_clk_init_struct;
+
+ HAL_RCCEx_GetPeriphCLKConfig(&rcc_ex_clk_init_struct);
+
+ /* Set the PLL configuration according to the audio frequency */
+ if((AudioFreq == AUDIO_FREQUENCY_11K) || (AudioFreq == AUDIO_FREQUENCY_22K) || (AudioFreq == AUDIO_FREQUENCY_44K))
+ {
+ /* Configure PLLSAI prescalers */
+ /* PLLI2S_VCO: VCO_429M
+ SAI_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 429/2 = 214.5 Mhz
+ SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ = 214.5/19 = 11.289 Mhz */
+ rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
+ rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S;
+ rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 429;
+ rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 2;
+ rcc_ex_clk_init_struct.PLLI2SDivQ = 19;
+
+ HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct);
+
+ }
+ else /* AUDIO_FREQUENCY_8K, AUDIO_FREQUENCY_16K, AUDIO_FREQUENCY_32K, AUDIO_FREQUENCY_48K, AUDIO_FREQUENCY_96K */
+ {
+ /* SAI clock config
+ PLLI2S_VCO: VCO_344M
+ SAI_CLK(first level) = PLLI2S_VCO/PLLI2SQ = 344/7 = 49.142 Mhz
+ SAI_CLK_x = SAI_CLK(first level)/PLLI2SDIVQ = 49.142/1 = 49.142 Mhz */
+ rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_SAI2;
+ rcc_ex_clk_init_struct.Sai2ClockSelection = RCC_SAI2CLKSOURCE_PLLI2S;
+ rcc_ex_clk_init_struct.PLLI2S.PLLI2SN = 344;
+ rcc_ex_clk_init_struct.PLLI2S.PLLI2SQ = 7;
+ rcc_ex_clk_init_struct.PLLI2SDivQ = 1;
+ HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct);
+ }
+
+ rcc_ex_clk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_DFSDM1_AUDIO;
+ rcc_ex_clk_init_struct.Dfsdm1AudioClockSelection = RCC_DFSDM1AUDIOCLKSOURCE_SAI2;
+ HAL_RCCEx_PeriphCLKConfig(&rcc_ex_clk_init_struct);
+}
+
+/*******************************************************************************
+ Static Functions
+*******************************************************************************/
+/**
+ * @brief Initialize the Digital Filter for Sigma-Delta Modulators interface (DFSDM).
+ * @param AudioFreq: Audio frequency to be used to set correctly the DFSDM peripheral.
+ * @note Channel output Clock Divider and Filter Oversampling are calculated as follow:
+ * - Clock_Divider = CLK(input DFSDM)/CLK(micro) with
+ * 1MHZ < CLK(micro) < 3.2MHZ (TYP 2.4MHZ for MP34DT01TR)
+ * - Oversampling = CLK(input DFSDM)/(Clock_Divider * AudioFreq)
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+static uint8_t DFSDMx_Init(uint32_t AudioFreq)
+{
+ /****************************************************************************/
+ /********************** Channels configuration *****************************/
+ /****************************************************************************/
+ /* CHANNEL 1 configuration */
+ __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&hAudioInTopLeftChannel);
+ hAudioInTopLeftChannel.Instance = DFSDM1_Channel1;
+ hAudioInTopLeftChannel.Init.OutputClock.Activation = ENABLE;
+ hAudioInTopLeftChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
+ /* Set the DFSDM clock OUT audio frequency configuration */
+ hAudioInTopLeftChannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq);
+ hAudioInTopLeftChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
+ hAudioInTopLeftChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
+ hAudioInTopLeftChannel.Init.Input.Pins = DFSDM_CHANNEL_SAME_CHANNEL_PINS;
+ /* Request to sample stable data for LEFT micro on Rising edge */
+ hAudioInTopLeftChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING;
+ hAudioInTopLeftChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
+ hAudioInTopLeftChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER;
+ hAudioInTopLeftChannel.Init.Awd.Oversampling = 10;
+ hAudioInTopLeftChannel.Init.Offset = 0;
+ hAudioInTopLeftChannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq);
+ if(HAL_OK != HAL_DFSDM_ChannelInit(&hAudioInTopLeftChannel))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* CHANNEL 0 configuration */
+ __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&hAudioInTopRightChannel);
+ hAudioInTopRightChannel.Instance = DFSDM1_Channel0;
+ hAudioInTopRightChannel.Init.OutputClock.Activation = ENABLE;
+ hAudioInTopRightChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
+ /* Set the DFSDM clock OUT audio frequency configuration */
+ hAudioInTopRightChannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq);
+ hAudioInTopRightChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
+ hAudioInTopRightChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
+ hAudioInTopRightChannel.Init.Input.Pins = DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS;
+ /* Request to sample stable data for RIGHT micro on Falling edge */
+ hAudioInTopRightChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_FALLING;
+ hAudioInTopRightChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
+ hAudioInTopRightChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER;
+ hAudioInTopRightChannel.Init.Awd.Oversampling = 10;
+ hAudioInTopRightChannel.Init.Offset = 0;
+ hAudioInTopRightChannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq);
+ if(HAL_OK != HAL_DFSDM_ChannelInit(&hAudioInTopRightChannel))
+ {
+ return AUDIO_ERROR;
+ }
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /* CHANNEL 5 configuration */
+ __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&hAudioInButtomLeftChannel);
+ hAudioInButtomLeftChannel.Instance = DFSDM1_Channel5;
+ hAudioInButtomLeftChannel.Init.OutputClock.Activation = ENABLE;
+ hAudioInButtomLeftChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
+ /* Set the DFSDM clock OUT audio frequency configuration */
+ hAudioInButtomLeftChannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq);
+ hAudioInButtomLeftChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
+ hAudioInButtomLeftChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
+ hAudioInButtomLeftChannel.Init.Input.Pins = DFSDM_CHANNEL_SAME_CHANNEL_PINS;
+ /* Request to sample stable data for LEFT micro on Rising edge */
+ hAudioInButtomLeftChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING;
+ hAudioInButtomLeftChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
+ hAudioInButtomLeftChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER;
+ hAudioInButtomLeftChannel.Init.Awd.Oversampling = 10;
+ hAudioInButtomLeftChannel.Init.Offset = 0;
+ hAudioInButtomLeftChannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq);
+ if(HAL_OK != HAL_DFSDM_ChannelInit(&hAudioInButtomLeftChannel))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* CHANNEL 4 configuration */
+ __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&hAudioInButtomRightChannel);
+ hAudioInButtomRightChannel.Instance = DFSDM1_Channel4;
+ hAudioInButtomRightChannel.Init.OutputClock.Activation = ENABLE;
+ hAudioInButtomRightChannel.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO;
+ /* Set the DFSDM clock OUT audio frequency configuration */
+ hAudioInButtomRightChannel.Init.OutputClock.Divider = DFSDM_CLOCK_DIVIDER(AudioFreq);
+ hAudioInButtomRightChannel.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS;
+ hAudioInButtomRightChannel.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE;
+ hAudioInButtomRightChannel.Init.Input.Pins = DFSDM_CHANNEL_FOLLOWING_CHANNEL_PINS;
+ /* Request to sample stable data for RIGHT micro on Falling edge */
+ hAudioInButtomRightChannel.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_FALLING;
+ hAudioInButtomRightChannel.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL;
+ hAudioInButtomRightChannel.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER;
+ hAudioInButtomRightChannel.Init.Awd.Oversampling = 10;
+ hAudioInButtomRightChannel.Init.Offset = 0;
+ hAudioInButtomRightChannel.Init.RightBitShift = DFSDM_RIGHT_BIT_SHIFT(AudioFreq);
+ if(HAL_OK != HAL_DFSDM_ChannelInit(&hAudioInButtomRightChannel))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ /****************************************************************************/
+ /********************** Filters configuration ******************************/
+ /****************************************************************************/
+
+ /* FILTER 0 configuration */
+ __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&hAudioInTopLeftFilter);
+ hAudioInTopLeftFilter.Instance = AUDIO_DFSDMx_TOP_LEFT_FILTER;
+ hAudioInTopLeftFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
+ hAudioInTopLeftFilter.Init.RegularParam.FastMode = ENABLE;
+ hAudioInTopLeftFilter.Init.RegularParam.DmaMode = ENABLE;
+ hAudioInTopLeftFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
+ hAudioInTopLeftFilter.Init.InjectedParam.ScanMode = ENABLE;
+ hAudioInTopLeftFilter.Init.InjectedParam.DmaMode = DISABLE;
+ hAudioInTopLeftFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO;
+ hAudioInTopLeftFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE;
+ hAudioInTopLeftFilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq);
+ /* Set the DFSDM Filters Oversampling to have correct sample rate */
+ hAudioInTopLeftFilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq);
+ hAudioInTopLeftFilter.Init.FilterParam.IntOversampling = 1;
+ if(HAL_OK != HAL_DFSDM_FilterInit(&hAudioInTopLeftFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Configure injected channel */
+ if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&hAudioInTopLeftFilter, AUDIO_DFSDMx_TOP_LEFT_CHANNEL, DFSDM_CONTINUOUS_CONV_ON))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* FILTER 1 configuration */
+ __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&hAudioInTopRightFilter);
+ hAudioInTopRightFilter.Instance = AUDIO_DFSDMx_TOP_RIGHT_FILTER;
+ hAudioInTopRightFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SYNC_TRIGGER;
+ hAudioInTopRightFilter.Init.RegularParam.FastMode = ENABLE;
+ hAudioInTopRightFilter.Init.RegularParam.DmaMode = ENABLE;
+ hAudioInTopRightFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
+ hAudioInTopRightFilter.Init.InjectedParam.ScanMode = DISABLE;
+ hAudioInTopRightFilter.Init.InjectedParam.DmaMode = DISABLE;
+ hAudioInTopRightFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO;
+ hAudioInTopRightFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE;
+ hAudioInTopRightFilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq);
+ /* Set the DFSDM Filters Oversampling to have correct sample rate */
+ hAudioInTopRightFilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq);
+ hAudioInTopRightFilter.Init.FilterParam.IntOversampling = 1;
+ if(HAL_OK != HAL_DFSDM_FilterInit(&hAudioInTopRightFilter))
+ {
+ return AUDIO_ERROR;
+ }
+ /* Configure injected channel */
+ if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&hAudioInTopRightFilter, AUDIO_DFSDMx_TOP_RIGHT_CHANNEL, DFSDM_CONTINUOUS_CONV_ON))
+ {
+ return AUDIO_ERROR;
+ }
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /* FILTER 2 configuration */
+ __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&hAudioInButtomLeftFilter);
+ hAudioInButtomLeftFilter.Instance = AUDIO_DFSDMx_BUTTOM_LEFT_FILTER;
+ hAudioInButtomLeftFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SYNC_TRIGGER;
+ hAudioInButtomLeftFilter.Init.RegularParam.FastMode = ENABLE;
+ hAudioInButtomLeftFilter.Init.RegularParam.DmaMode = ENABLE;
+ hAudioInButtomLeftFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
+ hAudioInButtomLeftFilter.Init.InjectedParam.ScanMode = ENABLE;
+ hAudioInButtomLeftFilter.Init.InjectedParam.DmaMode = DISABLE;
+ hAudioInButtomLeftFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO;
+ hAudioInButtomLeftFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE;
+ hAudioInButtomLeftFilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq);
+ /* Set the DFSDM Filters Oversampling to have correct sample rate */
+ hAudioInButtomLeftFilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq);
+ hAudioInButtomLeftFilter.Init.FilterParam.IntOversampling = 1;
+ if(HAL_OK != HAL_DFSDM_FilterInit(&hAudioInButtomLeftFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* Configure injected channel */
+ if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&hAudioInButtomLeftFilter, AUDIO_DFSDMx_BUTTOM_LEFT_CHANNEL, DFSDM_CONTINUOUS_CONV_ON))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* FILTER 3 configuration */
+ __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&hAudioInButtomRightFilter);
+ hAudioInButtomRightFilter.Instance = AUDIO_DFSDMx_BUTTOM_RIGHT_FILTER;
+ hAudioInButtomRightFilter.Init.RegularParam.Trigger = DFSDM_FILTER_SYNC_TRIGGER;
+ hAudioInButtomRightFilter.Init.RegularParam.FastMode = ENABLE;
+ hAudioInButtomRightFilter.Init.RegularParam.DmaMode = ENABLE;
+ hAudioInButtomRightFilter.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER;
+ hAudioInButtomRightFilter.Init.InjectedParam.ScanMode = DISABLE;
+ hAudioInButtomRightFilter.Init.InjectedParam.DmaMode = DISABLE;
+ hAudioInButtomRightFilter.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO;
+ hAudioInButtomRightFilter.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE;
+ hAudioInButtomRightFilter.Init.FilterParam.SincOrder = DFSDM_FILTER_ORDER(AudioFreq);
+ /* Set the DFSDM Filters Oversampling to have correct sample rate */
+ hAudioInButtomRightFilter.Init.FilterParam.Oversampling = DFSDM_OVER_SAMPLING(AudioFreq);
+ hAudioInButtomRightFilter.Init.FilterParam.IntOversampling = 1;
+ if(HAL_OK != HAL_DFSDM_FilterInit(&hAudioInButtomRightFilter))
+ {
+ return AUDIO_ERROR;
+ }
+ /* Configure injected channel */
+ if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&hAudioInButtomRightFilter, AUDIO_DFSDMx_BUTTOM_RIGHT_CHANNEL, DFSDM_CONTINUOUS_CONV_ON))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+ return AUDIO_OK;
+}
+
+/**
+ * @brief De-initialize the Digital Filter for Sigma-Delta Modulators interface (DFSDM).
+ * @retval AUDIO_OK if correct communication, else wrong communication
+ */
+static uint8_t DFSDMx_DeInit(void)
+{
+ /* De-initializes the DFSDM filters to allow access to DFSDM internal registers */
+ if(HAL_OK != HAL_DFSDM_FilterDeInit(&hAudioInTopLeftFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ if(HAL_OK != HAL_DFSDM_FilterDeInit(&hAudioInTopRightFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* De-initializes the DFSDM channels to allow access to DFSDM internal registers */
+ if(HAL_OK != HAL_DFSDM_ChannelDeInit(&hAudioInTopLeftChannel))
+ {
+ return AUDIO_ERROR;
+ }
+
+ if(HAL_OK != HAL_DFSDM_ChannelDeInit(&hAudioInTopRightChannel))
+ {
+ return AUDIO_ERROR;
+ }
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /* De-initializes the DFSDM filters to allow access to DFSDM internal registers */
+ if(HAL_OK != HAL_DFSDM_FilterDeInit(&hAudioInButtomLeftFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ if(HAL_OK != HAL_DFSDM_FilterDeInit(&hAudioInButtomRightFilter))
+ {
+ return AUDIO_ERROR;
+ }
+
+ /* De-initializes the DFSDM channels to allow access to DFSDM internal registers */
+ if(HAL_OK != HAL_DFSDM_ChannelDeInit(&hAudioInButtomLeftChannel))
+ {
+ return AUDIO_ERROR;
+ }
+
+ if(HAL_OK != HAL_DFSDM_ChannelDeInit(&hAudioInButtomRightChannel))
+ {
+ return AUDIO_ERROR;
+ }
+ }
+
+ return AUDIO_OK;
+}
+
+/**
+ * @brief Initialize the DFSDM channel MSP.
+ * @retval None
+ */
+static void DFSDMx_ChannelMspInit(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* Enable DFSDM clock */
+ AUDIO_DFSDMx_CLK_ENABLE();
+
+ /* Enable GPIO clock */
+ AUDIO_DFSDMx_DMIC_DATIN_GPIO_CLK_ENABLE();
+ AUDIO_DFSDMx_CKOUT_DMIC_GPIO_CLK_ENABLE();
+
+ /* DFSDM pins configuration: DFSDM_CKOUT, DMIC_DATIN1 pins ------------------*/
+ GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStruct.Alternate = AUDIO_DFSDMx_CKOUT_AF;
+ HAL_GPIO_Init(AUDIO_DFSDMx_CKOUT_DMIC_GPIO_PORT, &GPIO_InitStruct);
+
+ /* DFSDM pin configuration: DMIC_DATIN1 pin --------------------------------*/
+ GPIO_InitStruct.Pin = AUDIO_DFSDMx_DMIC_DATIN1_PIN;
+ GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DMIC_DATIN_AF;
+ HAL_GPIO_Init(AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct);
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /* DFSDM pin configuration: DMIC_DATIN5 pin --------------------------------*/
+ GPIO_InitStruct.Pin = AUDIO_DFSDMx_DMIC_DATIN5_PIN;
+ GPIO_InitStruct.Alternate = AUDIO_DFSDMx_DMIC_DATIN_AF;
+ HAL_GPIO_Init(AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT, &GPIO_InitStruct);
+ }
+}
+
+/**
+ * @brief DeInitialize the DFSDM channel MSP.
+ * @retval None
+ */
+static void DFSDMx_ChannelMspDeInit(void)
+{
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ /* DFSDM pin configuration: DMIC_DATIN1 pin --------------------------------*/
+ GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN;
+ HAL_GPIO_DeInit(AUDIO_DFSDMx_CKOUT_DMIC_GPIO_PORT, GPIO_InitStruct.Pin);
+ GPIO_InitStruct.Pin = AUDIO_DFSDMx_DMIC_DATIN1_PIN;
+ HAL_GPIO_DeInit(AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT, GPIO_InitStruct.Pin);
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /* DFSDM pin configuration: DMIC_DATIN5 pin ------------------------------*/
+ GPIO_InitStruct.Pin = AUDIO_DFSDMx_CKOUT_PIN;
+ HAL_GPIO_DeInit(AUDIO_DFSDMx_CKOUT_DMIC_GPIO_PORT, GPIO_InitStruct.Pin);
+ GPIO_InitStruct.Pin = AUDIO_DFSDMx_DMIC_DATIN5_PIN;
+ HAL_GPIO_DeInit(AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT, GPIO_InitStruct.Pin);
+ }
+}
+
+/**
+ * @brief Initialize the DFSDM filter MSP.
+ * @retval None
+ */
+static void DFSDMx_FilterMspInit(void)
+{
+ /* Enable DFSDM clock */
+ AUDIO_DFSDMx_CLK_ENABLE();
+
+ /* Enable the DMA clock */
+ AUDIO_DFSDMx_DMAx_CLK_ENABLE();
+
+ /*********** Configure DMA stream for TOP LEFT microphone *******************/
+ hDmaTopLeft.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hDmaTopLeft.Init.PeriphInc = DMA_PINC_DISABLE;
+ hDmaTopLeft.Init.MemInc = DMA_MINC_ENABLE;
+ hDmaTopLeft.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE;
+ hDmaTopLeft.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE;
+ hDmaTopLeft.Init.Mode = DMA_CIRCULAR;
+ hDmaTopLeft.Init.Priority = DMA_PRIORITY_HIGH;
+ hDmaTopLeft.Instance = AUDIO_DFSDMx_DMAx_TOP_LEFT_STREAM;
+ hDmaTopLeft.Init.Channel = AUDIO_DFSDMx_DMAx_CHANNEL;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(&hAudioInTopLeftFilter, hdmaReg, hDmaTopLeft);
+
+ /* Reset DMA handle state */
+ __HAL_DMA_RESET_HANDLE_STATE(&hDmaTopLeft);
+
+ /* Configure the DMA Channel */
+ HAL_DMA_Init(&hDmaTopLeft);
+
+ /* DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_TOP_LEFT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
+ HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_TOP_LEFT_IRQ);
+
+
+ /*********** Configure DMA stream for TOP RIGHT microphone ******************/
+ hDmaTopRight.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hDmaTopRight.Init.PeriphInc = DMA_PINC_DISABLE;
+ hDmaTopRight.Init.MemInc = DMA_MINC_ENABLE;
+ hDmaTopRight.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE;
+ hDmaTopRight.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE;
+ hDmaTopRight.Init.Mode = DMA_CIRCULAR;
+ hDmaTopRight.Init.Priority = DMA_PRIORITY_HIGH;
+ hDmaTopRight.Instance = AUDIO_DFSDMx_DMAx_TOP_RIGHT_STREAM;
+ hDmaTopRight.Init.Channel = AUDIO_DFSDMx_DMAx_CHANNEL;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(&hAudioInTopRightFilter, hdmaReg, hDmaTopRight);
+
+ /* Reset DMA handle state */
+ __HAL_DMA_RESET_HANDLE_STATE(&hDmaTopRight);
+
+ /* Configure the DMA Channel */
+ HAL_DMA_Init(&hDmaTopRight);
+
+ /* DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_TOP_RIGHT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
+ HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_TOP_RIGHT_IRQ);
+
+ if(AudioIn_ChannelNumber > 2)
+ {
+ /*********** Configure DMA stream for BUTTOM LEFT microphone ****************/
+ hDmaButtomLeft.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hDmaButtomLeft.Init.PeriphInc = DMA_PINC_DISABLE;
+ hDmaButtomLeft.Init.MemInc = DMA_MINC_ENABLE;
+ hDmaButtomLeft.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE;
+ hDmaButtomLeft.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE;
+ hDmaButtomLeft.Init.Mode = DMA_CIRCULAR;
+ hDmaButtomLeft.Init.Priority = DMA_PRIORITY_HIGH;
+ hDmaButtomLeft.Instance = AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_STREAM;
+ hDmaButtomLeft.Init.Channel = AUDIO_DFSDMx_DMAx_CHANNEL;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(&hAudioInButtomLeftFilter, hdmaReg, hDmaButtomLeft);
+
+ /* Reset DMA handle state */
+ __HAL_DMA_RESET_HANDLE_STATE(&hDmaButtomLeft);
+
+ /* Configure the DMA Channel */
+ HAL_DMA_Init(&hDmaButtomLeft);
+
+ /* DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
+ HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_IRQ);
+
+
+ /*********** Configure DMA stream for BUTTOM RIGHT microphone ***************/
+ hDmaButtomRight.Init.Direction = DMA_PERIPH_TO_MEMORY;
+ hDmaButtomRight.Init.PeriphInc = DMA_PINC_DISABLE;
+ hDmaButtomRight.Init.MemInc = DMA_MINC_ENABLE;
+ hDmaButtomRight.Init.PeriphDataAlignment = AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE;
+ hDmaButtomRight.Init.MemDataAlignment = AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE;
+ hDmaButtomRight.Init.Mode = DMA_CIRCULAR;
+ hDmaButtomRight.Init.Priority = DMA_PRIORITY_HIGH;
+ hDmaButtomRight.Instance = AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_STREAM;
+ hDmaButtomRight.Init.Channel = AUDIO_DFSDMx_DMAx_CHANNEL;
+
+ /* Associate the DMA handle */
+ __HAL_LINKDMA(&hAudioInButtomRightFilter, hdmaReg, hDmaButtomRight);
+
+ /* Reset DMA handle state */
+ __HAL_DMA_RESET_HANDLE_STATE(&hDmaButtomRight);
+
+ /* Configure the DMA Channel */
+ HAL_DMA_Init(&hDmaButtomRight);
+
+ /* DMA IRQ Channel configuration */
+ HAL_NVIC_SetPriority(AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_IRQ, AUDIO_OUT_IRQ_PREPRIO, 0);
+ HAL_NVIC_EnableIRQ(AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_IRQ);
+ }
+}
+
+/**
+ * @brief DeInitialize the DFSDM filter MSP.
+ * @retval None
+ */
+static void DFSDMx_FilterMspDeInit(void)
+{
+ /* Configure the DMA Channel */
+ HAL_DMA_DeInit(&hDmaTopLeft);
+ HAL_DMA_DeInit(&hDmaTopRight);
+ if(AudioIn_ChannelNumber > 2)
+ {
+ HAL_DMA_DeInit(&hDmaButtomLeft);
+ HAL_DMA_DeInit(&hDmaButtomRight);
+ }
+}
+
+
+/**
+ * @brief This function handles DMA2 Stream 0 interrupt request.
+ * @param None
+ * @retval None
+ */
+void AUDIO_DFSDMx_DMAx_TOP_LEFT_IRQHandler(void) // DMA2_Stream0_IRQHandler
+{
+ HAL_DMA_IRQHandler(hAudioInTopLeftFilter.hdmaReg);
+}
+
+/**
+ * @brief This function handles DMA2 Stream 5 interrupt request.
+ * @param None
+ * @retval None
+ */
+void AUDIO_DFSDMx_DMAx_TOP_RIGHT_IRQHandler(void) // DMA2_Stream5_IRQHandler
+{
+ HAL_DMA_IRQHandler(hAudioInTopRightFilter.hdmaReg);
+}
+
+/**
+ * @brief This function handles DMA2 Stream 1 interrupt request.
+ * @param None
+ * @retval None
+ */
+void AUDIO_OUT_SAIx_DMAx_IRQHandler(void) // DMA2_Stream1_IRQHandler
+{
+ HAL_DMA_IRQHandler(haudio_out_sai.hdmatx);
+}
+
+/**
+ * @brief This function handles DMA2 Stream 6 interrupt request.
+ * @param None
+ * @retval None
+ */
+void AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_IRQHandler(void) // DMA2_Stream6_IRQHandler
+{
+ HAL_DMA_IRQHandler(hAudioInButtomLeftFilter.hdmaReg);
+}
+
+/**
+ * @brief This function handles DMA2 Stream 7 interrupt request.
+ * @param None
+ * @retval None
+ */
+void AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_IRQHandler(void) // DMA2_Stream7_IRQHandler
+{
+ HAL_DMA_IRQHandler(hAudioInButtomRightFilter.hdmaReg);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
diff --git a/BSP/stm32f769i_discovery_audio.h b/BSP/stm32f769i_discovery_audio.h
new file mode 100644
index 0000000..c1e7a1c
--- /dev/null
+++ b/BSP/stm32f769i_discovery_audio.h
@@ -0,0 +1,324 @@
+/**
+ ******************************************************************************
+ * @file stm32f769i_discovery_audio.h
+ * @author MCD Application Team
+ * @brief This file contains the common defines and functions prototypes for
+ * the stm32f769i_discovery_audio.c driver.
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2016 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __STM32F769I_DISCOVERY_AUDIO_H
+#define __STM32F769I_DISCOVERY_AUDIO_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Includes ------------------------------------------------------------------*/
+/* Include audio component Driver */
+#include "wm8994.h"
+#include "stm32f769i_discovery.h"
+#include
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32F769I_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO STM32F769I_DISCOVERY_AUDIO
+ * @{
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_Exported_Types STM32F769I_DISCOVERY_AUDIO Exported Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_Exported_Constants STM32F769I_DISCOVERY_AUDIO Exported Constants
+ * @{
+ */
+
+/** @defgroup BSP_Audio_Sample_Rate BSP Audio Sample Rate
+ * @{
+ */
+#define BSP_AUDIO_FREQUENCY_96K SAI_AUDIO_FREQUENCY_96K
+#define BSP_AUDIO_FREQUENCY_48K SAI_AUDIO_FREQUENCY_48K
+#define BSP_AUDIO_FREQUENCY_44K SAI_AUDIO_FREQUENCY_44K
+#define BSP_AUDIO_FREQUENCY_32K SAI_AUDIO_FREQUENCY_32K
+#define BSP_AUDIO_FREQUENCY_22K SAI_AUDIO_FREQUENCY_22K
+#define BSP_AUDIO_FREQUENCY_16K SAI_AUDIO_FREQUENCY_16K
+#define BSP_AUDIO_FREQUENCY_11K SAI_AUDIO_FREQUENCY_11K
+#define BSP_AUDIO_FREQUENCY_8K SAI_AUDIO_FREQUENCY_8K
+/**
+ * @}
+ */
+
+/*------------------------------------------------------------------------------
+ USER SAI defines parameters
+ -----------------------------------------------------------------------------*/
+/** CODEC_AudioFrame_SLOT_TDMMode In W8994 codec the Audio frame contains 4 slots : TDM Mode
+ * TDM format :
+ * +------------------|------------------|--------------------|-------------------+
+ * | CODEC_SLOT0 Left | CODEC_SLOT1 Left | CODEC_SLOT0 Right | CODEC_SLOT1 Right |
+ * +------------------------------------------------------------------------------+
+ */
+/* To have 2 separate audio stream in Both headphone and speaker the 4 slot must be activated */
+#define CODEC_AUDIOFRAME_SLOT_0123 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_2 | SAI_SLOTACTIVE_3
+
+/* To have an audio stream in headphone only SAI Slot 0 and Slot 2 must be activated */
+#define CODEC_AUDIOFRAME_SLOT_02 SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_2
+/* To have an audio stream in speaker only SAI Slot 1 and Slot 3 must be activated */
+#define CODEC_AUDIOFRAME_SLOT_13 SAI_SLOTACTIVE_1 | SAI_SLOTACTIVE_3
+
+
+/* SAI peripheral configuration defines */
+#define AUDIO_OUT_SAIx SAI1_Block_A
+#define AUDIO_OUT_SAIx_CLK_ENABLE() __HAL_RCC_SAI1_CLK_ENABLE()
+#define AUDIO_OUT_SAIx_CLK_DISABLE() __HAL_RCC_SAI1_CLK_DISABLE()
+#define AUDIO_OUT_SAIx_AF GPIO_AF6_SAI1
+
+#define AUDIO_OUT_SAIx_MCLK_ENABLE() __HAL_RCC_GPIOG_CLK_ENABLE()
+#define AUDIO_OUT_SAIx_MCLK_GPIO_PORT GPIOG
+#define AUDIO_OUT_SAIx_MCLK_PIN GPIO_PIN_7
+#define AUDIO_OUT_SAIx_SD_FS_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
+#define AUDIO_OUT_SAIx_SD_FS_SCK_GPIO_PORT GPIOE
+#define AUDIO_OUT_SAIx_FS_PIN GPIO_PIN_4
+#define AUDIO_OUT_SAIx_SCK_PIN GPIO_PIN_5
+#define AUDIO_OUT_SAIx_SD_PIN GPIO_PIN_6
+
+/* SAI DMA Stream definitions */
+#define AUDIO_OUT_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE()
+#define AUDIO_OUT_SAIx_DMAx_STREAM DMA2_Stream1
+#define AUDIO_OUT_SAIx_DMAx_CHANNEL DMA_CHANNEL_0
+#define AUDIO_OUT_SAIx_DMAx_IRQ DMA2_Stream1_IRQn
+#define AUDIO_OUT_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD
+#define AUDIO_OUT_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD
+#define DMA_MAX_SZE 0xFFFF
+
+#define AUDIO_OUT_SAIx_DMAx_IRQHandler DMA2_Stream1_IRQHandler
+
+/* Select the interrupt preemption priority and subpriority for the DMA interrupt */
+#define AUDIO_OUT_IRQ_PREPRIO ((uint32_t)0x0E)
+
+/*------------------------------------------------------------------------------
+ AUDIO IN CONFIGURATION
+------------------------------------------------------------------------------*/
+/* SAI peripheral configuration defines */
+#define AUDIO_IN_SAIx SAI1_Block_B
+#define AUDIO_IN_SAIx_CLK_ENABLE() __HAL_RCC_SAI1_CLK_ENABLE()
+#define AUDIO_IN_SAIx_CLK_DISABLE() __HAL_RCC_SAI1_CLK_DISABLE()
+#define AUDIO_IN_SAIx_AF GPIO_AF6_SAI1
+#define AUDIO_IN_SAIx_SD_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE()
+#define AUDIO_IN_SAIx_SD_GPIO_PORT GPIOE
+#define AUDIO_IN_SAIx_SD_PIN GPIO_PIN_3
+
+/* SAI DMA Stream definitions */
+#define AUDIO_IN_SAIx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE()
+#define AUDIO_IN_SAIx_DMAx_STREAM DMA2_Stream4
+#define AUDIO_IN_SAIx_DMAx_CHANNEL DMA_CHANNEL_1
+#define AUDIO_IN_SAIx_DMAx_IRQ DMA2_Stream4_IRQn
+#define AUDIO_IN_SAIx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_HALFWORD
+#define AUDIO_IN_SAIx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_HALFWORD
+
+#define AUDIO_IN_INT_GPIO_ENABLE() __HAL_RCC_GPIOJ_CLK_ENABLE()
+#define AUDIO_IN_INT_GPIO_PORT GPIOJ
+#define AUDIO_IN_INT_GPIO_PIN GPIO_PIN_12
+#define AUDIO_IN_INT_IRQ EXTI15_10_IRQn
+
+/* DFSDM Configuration defines */
+#define AUDIO_DFSDMx_TOP_RIGHT_CHANNEL DFSDM_CHANNEL_0
+#define AUDIO_DFSDMx_TOP_LEFT_CHANNEL DFSDM_CHANNEL_1
+#define AUDIO_DFSDMx_BUTTOM_RIGHT_CHANNEL DFSDM_CHANNEL_4
+#define AUDIO_DFSDMx_BUTTOM_LEFT_CHANNEL DFSDM_CHANNEL_5
+
+#define AUDIO_DFSDMx_TOP_LEFT_FILTER DFSDM1_Filter0
+#define AUDIO_DFSDMx_TOP_RIGHT_FILTER DFSDM1_Filter1
+#define AUDIO_DFSDMx_BUTTOM_LEFT_FILTER DFSDM1_Filter2
+#define AUDIO_DFSDMx_BUTTOM_RIGHT_FILTER DFSDM1_Filter3
+
+#define AUDIO_DFSDMx_CLK_ENABLE() __HAL_RCC_DFSDM1_CLK_ENABLE()
+#define AUDIO_DFSDMx_CKOUT_PIN GPIO_PIN_3
+#define AUDIO_DFSDMx_CKOUT_DMIC_GPIO_PORT GPIOD
+#define AUDIO_DFSDMx_CKOUT_DMIC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
+#define AUDIO_DFSDMx_DMIC_DATIN1_PIN GPIO_PIN_3
+#define AUDIO_DFSDMx_DMIC_DATIN5_PIN GPIO_PIN_11
+#define AUDIO_DFSDMx_DMIC_DATIN_GPIO_PORT GPIOC
+#define AUDIO_DFSDMx_DMIC_DATIN_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
+#define AUDIO_DFSDMx_DMIC_DATIN_AF GPIO_AF3_DFSDM1
+#define AUDIO_DFSDMx_CKOUT_AF GPIO_AF3_DFSDM1
+
+/* DFSDM DMA Right and Left channels definitions */
+#define AUDIO_DFSDMx_DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE()
+#define AUDIO_DFSDMx_DMAx_CHANNEL DMA_CHANNEL_8
+#define AUDIO_DFSDMx_DMAx_PERIPH_DATA_SIZE DMA_PDATAALIGN_WORD
+#define AUDIO_DFSDMx_DMAx_MEM_DATA_SIZE DMA_MDATAALIGN_WORD
+
+#define AUDIO_DFSDMx_DMAx_TOP_LEFT_STREAM DMA2_Stream0
+#define AUDIO_DFSDMx_DMAx_TOP_LEFT_IRQ DMA2_Stream0_IRQn
+#define AUDIO_DFSDMx_DMAx_TOP_LEFT_IRQHandler DMA2_Stream0_IRQHandler
+
+#define AUDIO_DFSDMx_DMAx_TOP_RIGHT_STREAM DMA2_Stream5
+#define AUDIO_DFSDMx_DMAx_TOP_RIGHT_IRQ DMA2_Stream5_IRQn
+#define AUDIO_DFSDMx_DMAx_TOP_RIGHT_IRQHandler DMA2_Stream5_IRQHandler
+
+#define AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_STREAM DMA2_Stream6
+#define AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_IRQ DMA2_Stream6_IRQn
+#define AUDIO_DFSDMx_DMAx_BUTTOM_LEFT_IRQHandler DMA2_Stream6_IRQHandler
+
+#define AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_STREAM DMA2_Stream7
+#define AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_IRQ DMA2_Stream7_IRQn
+#define AUDIO_DFSDMx_DMAx_BUTTOM_RIGHT_IRQHandler DMA2_Stream7_IRQHandler
+
+/* Select the interrupt preemption priority and subpriority for the DMA interrupt */
+#define AUDIO_IN_IRQ_PREPRIO ((uint32_t)0x0F)
+
+
+/*------------------------------------------------------------------------------
+ CONFIGURATION: Audio Driver Configuration parameters
+------------------------------------------------------------------------------*/
+
+#define AUDIODATA_SIZE 2 /* 16-bits audio data size */
+
+/* Audio status definition */
+#define AUDIO_OK ((uint8_t)0)
+#define AUDIO_ERROR ((uint8_t)1)
+#define AUDIO_TIMEOUT ((uint8_t)2)
+
+/* Audio In default settings */
+#define DEFAULT_AUDIO_IN_FREQ BSP_AUDIO_FREQUENCY_16K
+#define DEFAULT_AUDIO_IN_BIT_RESOLUTION ((uint8_t)16)
+#define DEFAULT_AUDIO_IN_CHANNEL_NBR ((uint8_t)2)
+#define DEFAULT_AUDIO_IN_VOLUME ((uint16_t)64)
+
+/*------------------------------------------------------------------------------
+ OUTPUT DEVICES definition
+------------------------------------------------------------------------------*/
+/* Alias on existing output devices to adapt for 2 headphones output */
+#define OUTPUT_DEVICE_HEADPHONE1 OUTPUT_DEVICE_HEADPHONE
+#define OUTPUT_DEVICE_HEADPHONE2 OUTPUT_DEVICE_SPEAKER /* Headphone2 is connected to Speaker output of the wm8994 */
+
+/*------------------------------------------------------------------------------
+ INPUT DEVICES definition
+------------------------------------------------------------------------------*/
+/* MP34DT01TR digital microphone on PCB top side */
+#define INPUT_DEVICE_DIGITAL_MIC ((uint16_t)0)
+/* Analog microphone input from 3.5 audio jack connector */
+#define INPUT_DEVICE_ANALOG_MIC INPUT_DEVICE_INPUT_LINE_1
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_Exported_Macros STM32F769I_DISCOVERY_AUDIO Exported Macros
+ * @{
+ */
+#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE)
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_OUT_Exported_Functions STM32F769I_DISCOVERY_AUDIO_OUT Exported Functions
+ * @{
+ */
+uint8_t BSP_AUDIO_OUT_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq);
+void BSP_AUDIO_OUT_DeInit(void);
+uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint32_t Size);
+void BSP_AUDIO_OUT_ChangeBuffer(uint16_t *pData, uint16_t Size);
+uint8_t BSP_AUDIO_OUT_Pause(void);
+uint8_t BSP_AUDIO_OUT_Resume(void);
+uint8_t BSP_AUDIO_OUT_Stop(uint32_t Option);
+uint8_t BSP_AUDIO_OUT_SetVolume(uint8_t Volume);
+void BSP_AUDIO_OUT_SetFrequency(uint32_t AudioFreq);
+void BSP_AUDIO_OUT_SetAudioFrameSlot(uint32_t AudioFrameSlot);
+uint8_t BSP_AUDIO_OUT_SetMute(uint32_t Cmd);
+uint8_t BSP_AUDIO_OUT_SetOutputMode(uint8_t Output);
+
+/* User Callbacks: user has to implement these functions in his code if they are needed. */
+/* This function is called when the requested data has been completely transferred.*/
+void BSP_AUDIO_OUT_TransferComplete_CallBack(void);
+
+/* This function is called when half of the requested buffer has been transferred. */
+void BSP_AUDIO_OUT_HalfTransfer_CallBack(void);
+
+/* This function is called when an Interrupt due to transfer error on or peripheral
+ error occurs. */
+void BSP_AUDIO_OUT_Error_CallBack(void);
+
+/* These function can be modified in case the current settings (e.g. DMA stream)
+ need to be changed for specific application needs */
+void BSP_AUDIO_OUT_ClockConfig(SAI_HandleTypeDef *hsai, uint32_t AudioFreq, void *Params);
+void BSP_AUDIO_OUT_MspInit(SAI_HandleTypeDef *hsai, void *Params);
+void BSP_AUDIO_OUT_MspDeInit(SAI_HandleTypeDef *hsai, void *Params);
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32F769I_DISCOVERY_AUDIO_IN_Exported_Functions STM32F769I_DISCOVERY_AUDIO_IN Exported Functions
+ * @{
+ */
+uint8_t BSP_AUDIO_IN_Init(uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr);
+uint8_t BSP_AUDIO_IN_InitEx(uint16_t InputDevice, uint32_t AudioFreq, uint32_t BitRes, uint32_t ChnlNbr);
+uint8_t BSP_AUDIO_IN_AllocScratch (int32_t *pScratch, uint32_t size);
+uint8_t BSP_AUDIO_IN_GetChannelNumber(void);
+void BSP_AUDIO_IN_DeInit(void);
+uint8_t BSP_AUDIO_IN_Record(uint16_t *pData, uint32_t Size);
+uint8_t BSP_AUDIO_IN_Stop(void);
+uint8_t BSP_AUDIO_IN_Pause(void);
+uint8_t BSP_AUDIO_IN_Resume(void);
+
+/* User Callbacks: user has to implement these functions in his code if they are needed. */
+/* This function should be implemented by the user application.
+ It is called into this driver when the current buffer is filled to prepare the next
+ buffer pointer and its size. */
+void BSP_AUDIO_IN_TransferComplete_CallBack(void);
+void BSP_AUDIO_IN_HalfTransfer_CallBack(void);
+
+/* This function is called when an Interrupt due to transfer error on or peripheral
+ error occurs. */
+void BSP_AUDIO_IN_Error_CallBack(void);
+
+/* These function can be modified in case the current settings (e.g. DMA stream)
+ need to be changed for specific application needs */
+void BSP_AUDIO_IN_ClockConfig(DFSDM_Filter_HandleTypeDef *hdfsdm_filter, uint32_t AudioFreq, void *Params);
+void BSP_AUDIO_IN_MspInit(void);
+void BSP_AUDIO_IN_MspDeInit(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __STM32F769I_DISCOVERY_AUDIO_H */
+
diff --git a/BSP/wm8994.c b/BSP/wm8994.c
new file mode 100644
index 0000000..44226fa
--- /dev/null
+++ b/BSP/wm8994.c
@@ -0,0 +1,1075 @@
+/**
+ ******************************************************************************
+ * @file wm8994.c
+ * @author MCD Application Team
+ * @brief This file provides the WM8994 Audio Codec driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT(c) 2016 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "wm8994.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup Components
+ * @{
+ */
+
+/** @addtogroup wm8994
+ * @brief This file provides a set of functions needed to drive the
+ * WM8994 audio codec.
+ * @{
+ */
+
+/** @defgroup WM8994_Private_Types
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup WM8994_Private_Defines
+ * @{
+ */
+/* Uncomment this line to enable verifying data sent to codec after each write
+ operation (for debug purpose) */
+#if !defined (VERIFY_WRITTENDATA)
+/*#define VERIFY_WRITTENDATA*/
+#endif /* VERIFY_WRITTENDATA */
+/**
+ * @}
+ */
+
+/** @defgroup WM8994_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup WM8994_Private_Variables
+ * @{
+ */
+
+/* Audio codec driver structure initialization */
+AUDIO_DrvTypeDef wm8994_drv =
+{
+ wm8994_Init,
+ wm8994_DeInit,
+ wm8994_ReadID,
+
+ wm8994_Play,
+ wm8994_Pause,
+ wm8994_Resume,
+ wm8994_Stop,
+
+ wm8994_SetFrequency,
+ wm8994_SetVolume,
+ wm8994_SetMute,
+ wm8994_SetOutputMode,
+
+ wm8994_Reset
+};
+
+static uint32_t outputEnabled = 0;
+static uint32_t inputEnabled = 0;
+static uint8_t ColdStartup = 1;
+
+/**
+ * @}
+ */
+
+/** @defgroup WM8994_Function_Prototypes
+ * @{
+ */
+static uint8_t CODEC_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value);
+/**
+ * @}
+ */
+
+
+/** @defgroup WM8994_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Initializes the audio codec and the control interface.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @param OutputInputDevice: can be OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
+ * OUTPUT_DEVICE_BOTH, OUTPUT_DEVICE_AUTO, INPUT_DEVICE_DIGITAL_MICROPHONE_1,
+ * INPUT_DEVICE_DIGITAL_MICROPHONE_2, INPUT_DEVICE_DIGITAL_MIC1_MIC2,
+ * INPUT_DEVICE_INPUT_LINE_1 or INPUT_DEVICE_INPUT_LINE_2.
+ * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max))
+ * @param AudioFreq: Audio Frequency
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_Init(uint16_t DeviceAddr, uint16_t OutputInputDevice, uint8_t Volume, uint32_t AudioFreq)
+{
+ uint32_t counter = 0;
+ uint16_t output_device = OutputInputDevice & 0xFF;
+ uint16_t input_device = OutputInputDevice & 0xFF00;
+ uint16_t power_mgnt_reg_1 = 0;
+
+ /* Initialize the Control interface of the Audio Codec */
+ AUDIO_IO_Init();
+ /* wm8994 Errata Work-Arounds */
+ counter += CODEC_IO_Write(DeviceAddr, 0x102, 0x0003);
+ counter += CODEC_IO_Write(DeviceAddr, 0x817, 0x0000);
+ counter += CODEC_IO_Write(DeviceAddr, 0x102, 0x0000);
+
+ /* Enable VMID soft start (fast), Start-up Bias Current Enabled */
+ counter += CODEC_IO_Write(DeviceAddr, 0x39, 0x006C);
+
+ /* Enable bias generator, Enable VMID */
+ if (input_device > 0)
+ {
+ counter += CODEC_IO_Write(DeviceAddr, 0x01, 0x0013);
+ }
+ else
+ {
+ counter += CODEC_IO_Write(DeviceAddr, 0x01, 0x0003);
+ }
+
+ /* Add Delay */
+ AUDIO_IO_Delay(50);
+
+ /* Path Configurations for output */
+ if (output_device > 0)
+ {
+ outputEnabled = 1;
+
+ switch (output_device)
+ {
+ case OUTPUT_DEVICE_SPEAKER:
+ /* Enable DAC1 (Left), Enable DAC1 (Right),
+ Disable DAC2 (Left), Disable DAC2 (Right)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0C0C);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0000);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0000);
+
+ /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002);
+
+ /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002);
+ break;
+
+ case OUTPUT_DEVICE_HEADPHONE:
+ /* Disable DAC1 (Left), Disable DAC1 (Right),
+ Enable DAC2 (Left), Enable DAC2 (Right)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001);
+
+ /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000);
+
+ /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000);
+ break;
+
+ case OUTPUT_DEVICE_BOTH:
+ if (input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2)
+ {
+ /* Enable DAC1 (Left), Enable DAC1 (Right),
+ also Enable DAC2 (Left), Enable DAC2 (Right)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303 | 0x0C0C);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path
+ Enable the AIF1 Timeslot 1 (Left) to DAC 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0003);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path
+ Enable the AIF1 Timeslot 1 (Right) to DAC 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0003);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 2 (Left) mixer path
+ Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0003);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 2 (Right) mixer path
+ Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0003);
+ }
+ else
+ {
+ /* Enable DAC1 (Left), Enable DAC1 (Right),
+ also Enable DAC2 (Left), Enable DAC2 (Right)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303 | 0x0C0C);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001);
+
+ /* Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002);
+
+ /* Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002);
+ }
+ break;
+
+ case OUTPUT_DEVICE_AUTO :
+ default:
+ /* Disable DAC1 (Left), Disable DAC1 (Right),
+ Enable DAC2 (Left), Enable DAC2 (Right)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001);
+
+ /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000);
+
+ /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000);
+ break;
+ }
+ }
+ else
+ {
+ outputEnabled = 0;
+ }
+
+ /* Path Configurations for input */
+ if (input_device > 0)
+ {
+ inputEnabled = 1;
+ switch (input_device)
+ {
+ case INPUT_DEVICE_DIGITAL_MICROPHONE_2 :
+ /* Enable AIF1ADC2 (Left), Enable AIF1ADC2 (Right)
+ * Enable DMICDAT2 (Left), Enable DMICDAT2 (Right)
+ * Enable Left ADC, Enable Right ADC */
+ counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0C30);
+
+ /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC2 Left/Right Timeslot 1 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x450, 0x00DB);
+
+ /* Disable IN1L, IN1R, IN2L, IN2R, Enable Thermal sensor & shutdown */
+ counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x6000);
+
+ /* Enable the DMIC2(Left) to AIF1 Timeslot 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x608, 0x0002);
+
+ /* Enable the DMIC2(Right) to AIF1 Timeslot 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x609, 0x0002);
+
+ /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC2 signal detect */
+ counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000E);
+ break;
+
+ case INPUT_DEVICE_INPUT_LINE_1 :
+ /* IN1LN_TO_IN1L, IN1LP_TO_VMID, IN1RN_TO_IN1R, IN1RP_TO_VMID */
+ counter += CODEC_IO_Write(DeviceAddr, 0x28, 0x0011);
+
+ /* Disable mute on IN1L_TO_MIXINL and +30dB on IN1L PGA output */
+ counter += CODEC_IO_Write(DeviceAddr, 0x29, 0x0035);
+
+ /* Disable mute on IN1R_TO_MIXINL, Gain = +30dB */
+ counter += CODEC_IO_Write(DeviceAddr, 0x2A, 0x0035);
+
+ /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right)
+ * Enable Left ADC, Enable Right ADC */
+ counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0303);
+
+ /* Enable AIF1 DRC1 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x440, 0x00DB);
+
+ /* Enable IN1L and IN1R, Disable IN2L and IN2R, Enable Thermal sensor & shutdown */
+ counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x6350);
+
+ /* Enable the ADCL(Left) to AIF1 Timeslot 0 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x606, 0x0002);
+
+ /* Enable the ADCR(Right) to AIF1 Timeslot 0 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x607, 0x0002);
+
+ /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */
+ counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000D);
+ break;
+
+ case INPUT_DEVICE_DIGITAL_MICROPHONE_1 :
+ /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right)
+ * Enable DMICDAT1 (Left), Enable DMICDAT1 (Right)
+ * Enable Left ADC, Enable Right ADC */
+ counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x030C);
+
+ /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x440, 0x00DB);
+
+ /* Disable IN1L, IN1R, IN2L, IN2R, Enable Thermal sensor & shutdown */
+ counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x6350);
+
+ /* Enable the DMIC2(Left) to AIF1 Timeslot 0 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x606, 0x0002);
+
+ /* Enable the DMIC2(Right) to AIF1 Timeslot 0 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x607, 0x0002);
+
+ /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */
+ counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000D);
+ break;
+ case INPUT_DEVICE_DIGITAL_MIC1_MIC2 :
+ /* Enable AIF1ADC1 (Left), Enable AIF1ADC1 (Right)
+ * Enable DMICDAT1 (Left), Enable DMICDAT1 (Right)
+ * Enable Left ADC, Enable Right ADC */
+ counter += CODEC_IO_Write(DeviceAddr, 0x04, 0x0F3C);
+
+ /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC2 Left/Right Timeslot 1 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x450, 0x00DB);
+
+ /* Enable AIF1 DRC2 Signal Detect & DRC in AIF1ADC1 Left/Right Timeslot 0 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x440, 0x00DB);
+
+ /* Disable IN1L, IN1R, Enable IN2L, IN2R, Thermal sensor & shutdown */
+ counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x63A0);
+
+ /* Enable the DMIC2(Left) to AIF1 Timeslot 0 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x606, 0x0002);
+
+ /* Enable the DMIC2(Right) to AIF1 Timeslot 0 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x607, 0x0002);
+
+ /* Enable the DMIC2(Left) to AIF1 Timeslot 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x608, 0x0002);
+
+ /* Enable the DMIC2(Right) to AIF1 Timeslot 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x609, 0x0002);
+
+ /* GPIO1 pin configuration GP1_DIR = output, GP1_FN = AIF1 DRC1 signal detect */
+ counter += CODEC_IO_Write(DeviceAddr, 0x700, 0x000D);
+ break;
+ case INPUT_DEVICE_INPUT_LINE_2 :
+ default:
+ /* Actually, no other input devices supported */
+ counter++;
+ break;
+ }
+ }
+ else
+ {
+ inputEnabled = 0;
+ }
+
+ /* Clock Configurations */
+ switch (AudioFreq)
+ {
+ case AUDIO_FREQUENCY_8K:
+ /* AIF1 Sample Rate = 8 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0003);
+ break;
+
+ case AUDIO_FREQUENCY_16K:
+ /* AIF1 Sample Rate = 16 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0033);
+ break;
+
+ case AUDIO_FREQUENCY_32K:
+ /* AIF1 Sample Rate = 32 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0063);
+ break;
+
+ case AUDIO_FREQUENCY_48K:
+ /* AIF1 Sample Rate = 48 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083);
+ break;
+
+ case AUDIO_FREQUENCY_96K:
+ /* AIF1 Sample Rate = 96 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x00A3);
+ break;
+
+ case AUDIO_FREQUENCY_11K:
+ /* AIF1 Sample Rate = 11.025 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0013);
+ break;
+
+ case AUDIO_FREQUENCY_22K:
+ /* AIF1 Sample Rate = 22.050 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0043);
+ break;
+
+ case AUDIO_FREQUENCY_44K:
+ /* AIF1 Sample Rate = 44.1 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0073);
+ break;
+
+ default:
+ /* AIF1 Sample Rate = 48 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083);
+ break;
+ }
+
+ if(input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2)
+ {
+ /* AIF1 Word Length = 16-bits, AIF1 Format = DSP mode */
+ counter += CODEC_IO_Write(DeviceAddr, 0x300, 0x4018);
+ }
+ else
+ {
+ /* AIF1 Word Length = 16-bits, AIF1 Format = I2S (Default Register Value) */
+ counter += CODEC_IO_Write(DeviceAddr, 0x300, 0x4010);
+ }
+
+ /* slave mode */
+ counter += CODEC_IO_Write(DeviceAddr, 0x302, 0x0000);
+
+ /* Enable the DSP processing clock for AIF1, Enable the core clock */
+ counter += CODEC_IO_Write(DeviceAddr, 0x208, 0x000A);
+
+ /* Enable AIF1 Clock, AIF1 Clock Source = MCLK1 pin */
+ counter += CODEC_IO_Write(DeviceAddr, 0x200, 0x0001);
+
+ if (output_device > 0) /* Audio output selected */
+ {
+ if (output_device == OUTPUT_DEVICE_HEADPHONE)
+ {
+ /* Select DAC1 (Left) to Left Headphone Output PGA (HPOUT1LVOL) path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x2D, 0x0100);
+
+ /* Select DAC1 (Right) to Right Headphone Output PGA (HPOUT1RVOL) path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x2E, 0x0100);
+
+ /* Startup sequence for Headphone */
+ if(ColdStartup)
+ {
+ counter += CODEC_IO_Write(DeviceAddr,0x110,0x8100);
+
+ ColdStartup=0;
+ /* Add Delay */
+ AUDIO_IO_Delay(300);
+ }
+ else /* Headphone Warm Start-Up */
+ {
+ counter += CODEC_IO_Write(DeviceAddr,0x110,0x8108);
+ /* Add Delay */
+ AUDIO_IO_Delay(50);
+ }
+
+ /* Soft un-Mute the AIF1 Timeslot 0 DAC1 path L&R */
+ counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0000);
+ }
+ /* Analog Output Configuration */
+
+ /* Enable SPKRVOL PGA, Enable SPKMIXR, Enable SPKLVOL PGA, Enable SPKMIXL */
+ counter += CODEC_IO_Write(DeviceAddr, 0x03, 0x0300);
+
+ /* Left Speaker Mixer Volume = 0dB */
+ counter += CODEC_IO_Write(DeviceAddr, 0x22, 0x0000);
+
+ /* Speaker output mode = Class D, Right Speaker Mixer Volume = 0dB ((0x23, 0x0100) = class AB)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x23, 0x0000);
+
+ /* Unmute DAC2 (Left) to Left Speaker Mixer (SPKMIXL) path,
+ Unmute DAC2 (Right) to Right Speaker Mixer (SPKMIXR) path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x36, 0x0300);
+
+ /* Enable bias generator, Enable VMID, Enable SPKOUTL, Enable SPKOUTR */
+ counter += CODEC_IO_Write(DeviceAddr, 0x01, 0x3003);
+
+ /* Headphone/Speaker Enable */
+
+ if (input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2)
+ {
+ /* Enable Class W, Class W Envelope Tracking = AIF1 Timeslots 0 and 1 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x51, 0x0205);
+ }
+ else
+ {
+ /* Enable Class W, Class W Envelope Tracking = AIF1 Timeslot 0 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x51, 0x0005);
+ }
+
+ /* Enable bias generator, Enable VMID, Enable HPOUT1 (Left) and Enable HPOUT1 (Right) input stages */
+ /* idem for Speaker */
+ power_mgnt_reg_1 |= 0x0303 | 0x3003;
+ counter += CODEC_IO_Write(DeviceAddr, 0x01, power_mgnt_reg_1);
+
+ /* Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate stages */
+ counter += CODEC_IO_Write(DeviceAddr, 0x60, 0x0022);
+
+ /* Enable Charge Pump */
+ counter += CODEC_IO_Write(DeviceAddr, 0x4C, 0x9F25);
+
+ /* Add Delay */
+ AUDIO_IO_Delay(15);
+
+ /* Select DAC1 (Left) to Left Headphone Output PGA (HPOUT1LVOL) path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x2D, 0x0001);
+
+ /* Select DAC1 (Right) to Right Headphone Output PGA (HPOUT1RVOL) path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x2E, 0x0001);
+
+ /* Enable Left Output Mixer (MIXOUTL), Enable Right Output Mixer (MIXOUTR) */
+ /* idem for SPKOUTL and SPKOUTR */
+ counter += CODEC_IO_Write(DeviceAddr, 0x03, 0x0030 | 0x0300);
+
+ /* Enable DC Servo and trigger start-up mode on left and right channels */
+ counter += CODEC_IO_Write(DeviceAddr, 0x54, 0x0033);
+
+ /* Add Delay */
+ AUDIO_IO_Delay(257);
+
+ /* Enable HPOUT1 (Left) and HPOUT1 (Right) intermediate and output stages. Remove clamps */
+ counter += CODEC_IO_Write(DeviceAddr, 0x60, 0x00EE);
+
+ /* Unmutes */
+
+ /* Unmute DAC 1 (Left) */
+ counter += CODEC_IO_Write(DeviceAddr, 0x610, 0x00C0);
+
+ /* Unmute DAC 1 (Right) */
+ counter += CODEC_IO_Write(DeviceAddr, 0x611, 0x00C0);
+
+ /* Unmute the AIF1 Timeslot 0 DAC path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0010);
+
+ /* Unmute DAC 2 (Left) */
+ counter += CODEC_IO_Write(DeviceAddr, 0x612, 0x00C0);
+
+ /* Unmute DAC 2 (Right) */
+ counter += CODEC_IO_Write(DeviceAddr, 0x613, 0x00C0);
+
+ /* Unmute the AIF1 Timeslot 1 DAC2 path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0010);
+
+ /* Volume Control */
+ wm8994_SetVolume(DeviceAddr, Volume);
+ }
+
+ if (input_device > 0) /* Audio input selected */
+ {
+ if ((input_device == INPUT_DEVICE_DIGITAL_MICROPHONE_1) || (input_device == INPUT_DEVICE_DIGITAL_MICROPHONE_2))
+ {
+ /* Enable Microphone bias 1 generator, Enable VMID */
+ power_mgnt_reg_1 |= 0x0013;
+ counter += CODEC_IO_Write(DeviceAddr, 0x01, power_mgnt_reg_1);
+
+ /* ADC oversample enable */
+ counter += CODEC_IO_Write(DeviceAddr, 0x620, 0x0002);
+
+ /* AIF ADC2 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */
+ counter += CODEC_IO_Write(DeviceAddr, 0x411, 0x3800);
+ }
+ else if(input_device == INPUT_DEVICE_DIGITAL_MIC1_MIC2)
+ {
+ /* Enable Microphone bias 1 generator, Enable VMID */
+ power_mgnt_reg_1 |= 0x0013;
+ counter += CODEC_IO_Write(DeviceAddr, 0x01, power_mgnt_reg_1);
+
+ /* ADC oversample enable */
+ counter += CODEC_IO_Write(DeviceAddr, 0x620, 0x0002);
+
+ /* AIF ADC1 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */
+ counter += CODEC_IO_Write(DeviceAddr, 0x410, 0x1800);
+
+ /* AIF ADC2 HPF enable, HPF cut = voice mode 1 fc=127Hz at fs=8kHz */
+ counter += CODEC_IO_Write(DeviceAddr, 0x411, 0x1800);
+ }
+ else if ((input_device == INPUT_DEVICE_INPUT_LINE_1) || (input_device == INPUT_DEVICE_INPUT_LINE_2))
+ {
+
+ /* Disable mute on IN1L, IN1L Volume = +0dB */
+ counter += CODEC_IO_Write(DeviceAddr, 0x18, 0x000B);
+
+ /* Disable mute on IN1R, IN1R Volume = +0dB */
+ counter += CODEC_IO_Write(DeviceAddr, 0x1A, 0x000B);
+
+ /* AIF ADC1 HPF enable, HPF cut = hifi mode fc=4Hz at fs=48kHz */
+ counter += CODEC_IO_Write(DeviceAddr, 0x410, 0x1800);
+ }
+ /* Volume Control */
+ wm8994_SetVolume(DeviceAddr, Volume);
+ }
+ /* Return communication control value */
+ return counter;
+}
+
+/**
+ * @brief Deinitializes the audio codec.
+ * @param None
+ * @retval None
+ */
+void wm8994_DeInit(void)
+{
+ /* Deinitialize Audio Codec interface */
+ AUDIO_IO_DeInit();
+}
+
+/**
+ * @brief Get the WM8994 ID.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @retval The WM8994 ID
+ */
+uint32_t wm8994_ReadID(uint16_t DeviceAddr)
+{
+ /* Initialize the Control interface of the Audio Codec */
+ AUDIO_IO_Init();
+
+ return ((uint32_t)AUDIO_IO_Read(DeviceAddr, WM8994_CHIPID_ADDR));
+}
+
+/**
+ * @brief Start the audio Codec play feature.
+ * @note For this codec no Play options are required.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size)
+{
+ uint32_t counter = 0;
+
+ /* Resumes the audio file playing */
+ /* Unmute the output first */
+ counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF);
+
+ return counter;
+}
+
+/**
+ * @brief Pauses playing on the audio codec.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_Pause(uint16_t DeviceAddr)
+{
+ uint32_t counter = 0;
+
+ /* Pause the audio file playing */
+ /* Mute the output first */
+ counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_ON);
+
+ /* Put the Codec in Power save mode */
+ counter += CODEC_IO_Write(DeviceAddr, 0x02, 0x01);
+
+ return counter;
+}
+
+/**
+ * @brief Resumes playing on the audio codec.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_Resume(uint16_t DeviceAddr)
+{
+ uint32_t counter = 0;
+
+ /* Resumes the audio file playing */
+ /* Unmute the output first */
+ counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF);
+
+ return counter;
+}
+
+/**
+ * @brief Stops audio Codec playing. It powers down the codec.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @param CodecPdwnMode: selects the power down mode.
+ * - CODEC_PDWN_SW: only mutes the audio codec. When resuming from this
+ * mode the codec keeps the previous initialization
+ * (no need to re-Initialize the codec registers).
+ * - CODEC_PDWN_HW: Physically power down the codec. When resuming from this
+ * mode, the codec is set to default configuration
+ * (user should re-Initialize the codec in order to
+ * play again the audio stream).
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_Stop(uint16_t DeviceAddr, uint32_t CodecPdwnMode)
+{
+ uint32_t counter = 0;
+
+ if (outputEnabled != 0)
+ {
+ /* Mute the output first */
+ counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_ON);
+
+ if (CodecPdwnMode == CODEC_PDWN_SW)
+ {
+ /* Only output mute required*/
+ }
+ else /* CODEC_PDWN_HW */
+ {
+ /* Mute the AIF1 Timeslot 0 DAC1 path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0200);
+
+ /* Mute the AIF1 Timeslot 1 DAC2 path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0200);
+
+ /* Disable DAC1L_TO_HPOUT1L */
+ counter += CODEC_IO_Write(DeviceAddr, 0x2D, 0x0000);
+
+ /* Disable DAC1R_TO_HPOUT1R */
+ counter += CODEC_IO_Write(DeviceAddr, 0x2E, 0x0000);
+
+ /* Disable DAC1 and DAC2 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0000);
+
+ /* Reset Codec by writing in 0x0000 address register */
+ counter += CODEC_IO_Write(DeviceAddr, 0x0000, 0x0000);
+
+ outputEnabled = 0;
+ }
+ }
+ return counter;
+}
+
+/**
+ * @brief Sets higher or lower the codec volume level.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @param Volume: a byte value from 0 to 255 (refer to codec registers
+ * description for more details).
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_SetVolume(uint16_t DeviceAddr, uint8_t Volume)
+{
+ uint32_t counter = 0;
+ uint8_t convertedvol = VOLUME_CONVERT(Volume);
+
+ /* Output volume */
+ if (outputEnabled != 0)
+ {
+ if(convertedvol > 0x3E)
+ {
+ /* Unmute audio codec */
+ counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF);
+
+ /* Left Headphone Volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x1C, 0x3F | 0x140);
+
+ /* Right Headphone Volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x1D, 0x3F | 0x140);
+
+ /* Left Speaker Volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x26, 0x3F | 0x140);
+
+ /* Right Speaker Volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x27, 0x3F | 0x140);
+ }
+ else if (Volume == 0)
+ {
+ /* Mute audio codec */
+ counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_ON);
+ }
+ else
+ {
+ /* Unmute audio codec */
+ counter += wm8994_SetMute(DeviceAddr, AUDIO_MUTE_OFF);
+
+ /* Left Headphone Volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x1C, convertedvol | 0x140);
+
+ /* Right Headphone Volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x1D, convertedvol | 0x140);
+
+ /* Left Speaker Volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x26, convertedvol | 0x140);
+
+ /* Right Speaker Volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x27, convertedvol | 0x140);
+ }
+ }
+
+ /* Input volume */
+ if (inputEnabled != 0)
+ {
+ convertedvol = VOLUME_IN_CONVERT(Volume);
+
+ /* Left AIF1 ADC1 volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x400, convertedvol | 0x100);
+
+ /* Right AIF1 ADC1 volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x401, convertedvol | 0x100);
+
+ /* Left AIF1 ADC2 volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x404, convertedvol | 0x100);
+
+ /* Right AIF1 ADC2 volume */
+ counter += CODEC_IO_Write(DeviceAddr, 0x405, convertedvol | 0x100);
+ }
+ return counter;
+}
+
+/**
+ * @brief Enables or disables the mute feature on the audio codec.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @param Cmd: AUDIO_MUTE_ON to enable the mute or AUDIO_MUTE_OFF to disable the
+ * mute mode.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_SetMute(uint16_t DeviceAddr, uint32_t Cmd)
+{
+ uint32_t counter = 0;
+
+ if (outputEnabled != 0)
+ {
+ /* Set the Mute mode */
+ if(Cmd == AUDIO_MUTE_ON)
+ {
+ /* Soft Mute the AIF1 Timeslot 0 DAC1 path L&R */
+ counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0200);
+
+ /* Soft Mute the AIF1 Timeslot 1 DAC2 path L&R */
+ counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0200);
+ }
+ else /* AUDIO_MUTE_OFF Disable the Mute */
+ {
+ /* Unmute the AIF1 Timeslot 0 DAC1 path L&R */
+ counter += CODEC_IO_Write(DeviceAddr, 0x420, 0x0010);
+
+ /* Unmute the AIF1 Timeslot 1 DAC2 path L&R */
+ counter += CODEC_IO_Write(DeviceAddr, 0x422, 0x0010);
+ }
+ }
+ return counter;
+}
+
+/**
+ * @brief Switch dynamically (while audio file is played) the output target
+ * (speaker or headphone).
+ * @param DeviceAddr: Device address on communication Bus.
+ * @param Output: specifies the audio output target: OUTPUT_DEVICE_SPEAKER,
+ * OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_SetOutputMode(uint16_t DeviceAddr, uint8_t Output)
+{
+ uint32_t counter = 0;
+
+ switch (Output)
+ {
+ case OUTPUT_DEVICE_SPEAKER:
+ /* Enable DAC1 (Left), Enable DAC1 (Right),
+ Disable DAC2 (Left), Disable DAC2 (Right)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0C0C);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0000);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0000);
+
+ /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002);
+
+ /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002);
+ break;
+
+ case OUTPUT_DEVICE_HEADPHONE:
+ /* Disable DAC1 (Left), Disable DAC1 (Right),
+ Enable DAC2 (Left), Enable DAC2 (Right)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001);
+
+ /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000);
+
+ /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000);
+ break;
+
+ case OUTPUT_DEVICE_BOTH:
+ /* Enable DAC1 (Left), Enable DAC1 (Right),
+ also Enable DAC2 (Left), Enable DAC2 (Right)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303 | 0x0C0C);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001);
+
+ /* Enable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0002);
+
+ /* Enable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0002);
+ break;
+
+ default:
+ /* Disable DAC1 (Left), Disable DAC1 (Right),
+ Enable DAC2 (Left), Enable DAC2 (Right)*/
+ counter += CODEC_IO_Write(DeviceAddr, 0x05, 0x0303);
+
+ /* Enable the AIF1 Timeslot 0 (Left) to DAC 1 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x601, 0x0001);
+
+ /* Enable the AIF1 Timeslot 0 (Right) to DAC 1 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x602, 0x0001);
+
+ /* Disable the AIF1 Timeslot 1 (Left) to DAC 2 (Left) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x604, 0x0000);
+
+ /* Disable the AIF1 Timeslot 1 (Right) to DAC 2 (Right) mixer path */
+ counter += CODEC_IO_Write(DeviceAddr, 0x605, 0x0000);
+ break;
+ }
+ return counter;
+}
+
+/**
+ * @brief Sets new frequency.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq)
+{
+ uint32_t counter = 0;
+
+ /* Clock Configurations */
+ switch (AudioFreq)
+ {
+ case AUDIO_FREQUENCY_8K:
+ /* AIF1 Sample Rate = 8 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0003);
+ break;
+
+ case AUDIO_FREQUENCY_16K:
+ /* AIF1 Sample Rate = 16 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0033);
+ break;
+
+ case AUDIO_FREQUENCY_32K:
+ /* AIF1 Sample Rate = 32 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0063);
+ break;
+
+ case AUDIO_FREQUENCY_48K:
+ /* AIF1 Sample Rate = 48 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083);
+ break;
+
+ case AUDIO_FREQUENCY_96K:
+ /* AIF1 Sample Rate = 96 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x00A3);
+ break;
+
+ case AUDIO_FREQUENCY_11K:
+ /* AIF1 Sample Rate = 11.025 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0013);
+ break;
+
+ case AUDIO_FREQUENCY_22K:
+ /* AIF1 Sample Rate = 22.050 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0043);
+ break;
+
+ case AUDIO_FREQUENCY_44K:
+ /* AIF1 Sample Rate = 44.1 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0073);
+ break;
+
+ default:
+ /* AIF1 Sample Rate = 48 (KHz), ratio=256 */
+ counter += CODEC_IO_Write(DeviceAddr, 0x210, 0x0083);
+ break;
+ }
+ return counter;
+}
+
+/**
+ * @brief Resets wm8994 registers.
+ * @param DeviceAddr: Device address on communication Bus.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t wm8994_Reset(uint16_t DeviceAddr)
+{
+ uint32_t counter = 0;
+
+ /* Reset Codec by writing in 0x0000 address register */
+ counter = CODEC_IO_Write(DeviceAddr, 0x0000, 0x0000);
+ outputEnabled = 0;
+ inputEnabled=0;
+
+ return counter;
+}
+
+/**
+ * @brief Writes/Read a single data.
+ * @param Addr: I2C address
+ * @param Reg: Reg address
+ * @param Value: Data to be written
+ * @retval None
+ */
+static uint8_t CODEC_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value)
+{
+ uint32_t result = 0;
+
+ AUDIO_IO_Write(Addr, Reg, Value);
+
+#ifdef VERIFY_WRITTENDATA
+ /* Verify that the data has been correctly written */
+ result = (AUDIO_IO_Read(Addr, Reg) == Value)? 0:1;
+#endif /* VERIFY_WRITTENDATA */
+
+ return result;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/BSP/wm8994.h b/BSP/wm8994.h
new file mode 100644
index 0000000..9108d52
--- /dev/null
+++ b/BSP/wm8994.h
@@ -0,0 +1,186 @@
+/**
+ ******************************************************************************
+ * @file wm8994.h
+ * @author MCD Application Team
+ * @brief This file contains all the functions prototypes for the
+ * wm8994.c driver.
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT(c) 2016 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __WM8994_H
+#define __WM8994_H
+
+/* Includes ------------------------------------------------------------------*/
+#include "audio.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup Component
+ * @{
+ */
+
+/** @addtogroup WM8994
+ * @{
+ */
+
+/** @defgroup WM8994_Exported_Types
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup WM8994_Exported_Constants
+ * @{
+ */
+
+/******************************************************************************/
+/*************************** Codec User defines ******************************/
+/******************************************************************************/
+/* Codec output DEVICE */
+#define OUTPUT_DEVICE_SPEAKER ((uint16_t)0x0001)
+#define OUTPUT_DEVICE_HEADPHONE ((uint16_t)0x0002)
+#define OUTPUT_DEVICE_BOTH ((uint16_t)0x0003)
+#define OUTPUT_DEVICE_AUTO ((uint16_t)0x0004)
+#define INPUT_DEVICE_DIGITAL_MICROPHONE_1 ((uint16_t)0x0100)
+#define INPUT_DEVICE_DIGITAL_MICROPHONE_2 ((uint16_t)0x0200)
+#define INPUT_DEVICE_INPUT_LINE_1 ((uint16_t)0x0300)
+#define INPUT_DEVICE_INPUT_LINE_2 ((uint16_t)0x0400)
+#define INPUT_DEVICE_DIGITAL_MIC1_MIC2 ((uint16_t)0x0800)
+
+/* Volume Levels values */
+#define DEFAULT_VOLMIN 0x00
+#define DEFAULT_VOLMAX 0xFF
+#define DEFAULT_VOLSTEP 0x04
+
+#define AUDIO_PAUSE 0
+#define AUDIO_RESUME 1
+
+/* Codec POWER DOWN modes */
+#define CODEC_PDWN_HW 1
+#define CODEC_PDWN_SW 2
+
+/* MUTE commands */
+#define AUDIO_MUTE_ON 1
+#define AUDIO_MUTE_OFF 0
+
+/* AUDIO FREQUENCY */
+#define AUDIO_FREQUENCY_192K ((uint32_t)192000)
+#define AUDIO_FREQUENCY_96K ((uint32_t)96000)
+#define AUDIO_FREQUENCY_48K ((uint32_t)48000)
+#define AUDIO_FREQUENCY_44K ((uint32_t)44100)
+#define AUDIO_FREQUENCY_32K ((uint32_t)32000)
+#define AUDIO_FREQUENCY_22K ((uint32_t)22050)
+#define AUDIO_FREQUENCY_16K ((uint32_t)16000)
+#define AUDIO_FREQUENCY_11K ((uint32_t)11025)
+#define AUDIO_FREQUENCY_8K ((uint32_t)8000)
+
+#define VOLUME_CONVERT(Volume) (((Volume) > 100)? 100:((uint8_t)(((Volume) * 63) / 100)))
+#define VOLUME_IN_CONVERT(Volume) (((Volume) >= 100)? 239:((uint8_t)(((Volume) * 240) / 100)))
+
+/******************************************************************************/
+/****************************** REGISTER MAPPING ******************************/
+/******************************************************************************/
+/**
+ * @brief WM8994 ID
+ */
+#define WM8994_ID 0x8994
+
+/**
+ * @brief Device ID Register: Reading from this register will indicate device
+ * family ID 8994h
+ */
+#define WM8994_CHIPID_ADDR 0x00
+
+/**
+ * @}
+ */
+
+/** @defgroup WM8994_Exported_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup WM8994_Exported_Functions
+ * @{
+ */
+
+/*------------------------------------------------------------------------------
+ Audio Codec functions
+------------------------------------------------------------------------------*/
+/* High Layer codec functions */
+uint32_t wm8994_Init(uint16_t DeviceAddr, uint16_t OutputInputDevice, uint8_t Volume, uint32_t AudioFreq);
+void wm8994_DeInit(void);
+uint32_t wm8994_ReadID(uint16_t DeviceAddr);
+uint32_t wm8994_Play(uint16_t DeviceAddr, uint16_t* pBuffer, uint16_t Size);
+uint32_t wm8994_Pause(uint16_t DeviceAddr);
+uint32_t wm8994_Resume(uint16_t DeviceAddr);
+uint32_t wm8994_Stop(uint16_t DeviceAddr, uint32_t Cmd);
+uint32_t wm8994_SetVolume(uint16_t DeviceAddr, uint8_t Volume);
+uint32_t wm8994_SetMute(uint16_t DeviceAddr, uint32_t Cmd);
+uint32_t wm8994_SetOutputMode(uint16_t DeviceAddr, uint8_t Output);
+uint32_t wm8994_SetFrequency(uint16_t DeviceAddr, uint32_t AudioFreq);
+uint32_t wm8994_Reset(uint16_t DeviceAddr);
+
+/* AUDIO IO functions */
+void AUDIO_IO_Init(void);
+void AUDIO_IO_DeInit(void);
+void AUDIO_IO_Write(uint8_t Addr, uint16_t Reg, uint16_t Value);
+uint8_t AUDIO_IO_Read(uint8_t Addr, uint16_t Reg);
+void AUDIO_IO_Delay(uint32_t Delay);
+
+/* Audio driver structure */
+extern AUDIO_DrvTypeDef wm8994_drv;
+
+#endif /* __WM8994_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8d770c4..e34f896 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,12 +12,19 @@
# Globally enable some compiler sanity
add_compile_options(-fwrapv -fno-strict-aliasing -fsigned-char)
+# Create BSP project
+project(STBSP)
+file(GLOB BSP_FILES "${PROJECT_SOURCE_DIR}/BSP/*.c")
+add_library(STBSP STATIC ${BSP_FILES})
+target_link_libraries(STBSP PRIVATE mbed-os)
+target_include_directories(STBSP PUBLIC "${PROJECT_SOURCE_DIR}/BSP")
+
# Create Tardis project
project(Tardis)
file(GLOB SRC_FILES "${PROJECT_SOURCE_DIR}/src/*.cpp")
add_executable(Tardis ${SRC_FILES})
target_include_directories(Tardis PRIVATE "${PROJECT_SOURCE_DIR}/include")
-target_link_libraries(Tardis PRIVATE mbed-os mbed-storage-qspif mbed-usb-msd mbed-storage-littlefs-v2)
+target_link_libraries(Tardis PRIVATE mbed-os mbed-storage-qspif mbed-usb-msd mbed-storage-littlefs-v2 STBSP)
target_compile_options(Tardis PRIVATE -Wall -Wextra -Wpedantic -Werror)
mbed_set_post_build(Tardis)
diff --git a/include/ButtonThread.h b/include/ButtonThread.h
index 5d3a2d9..c2f7855 100644
--- a/include/ButtonThread.h
+++ b/include/ButtonThread.h
@@ -7,16 +7,9 @@
#define BUTTONTHREAD_H
#include "mbed.h"
-#include
-
-int readButtonPresses(void);
-
-void button_onrise(void);
void buttonTask(void);
-bool waitPressCondition(Kernel::Clock::time_point timeout);
-
int waitForPresses(std::chrono::milliseconds wait_time);
#endif // BUTTONTHREAD_H
diff --git a/include/Filesystem.h b/include/Filesystem.h
index d03d952..9b5ec30 100644
--- a/include/Filesystem.h
+++ b/include/Filesystem.h
@@ -6,9 +6,10 @@
#ifndef FILESYSTEM_H
#define FILESYSTEM_H
-#include "MainFilesystem.h"
+#include "FileSystem.h"
+#include "mbed.h"
-void mountFilesystem(mbed::BlockDevice &bd, LittleFileSystem2 &fs);
-void unmountFilesystem(mbed::BlockDevice &bd, LittleFileSystem2 &fs);
+void mountFilesystem(mbed::BlockDevice &bd, mbed::FileSystem &fs);
+void unmountFilesystem(mbed::BlockDevice &bd, mbed::FileSystem &fs);
#endif
diff --git a/include/FlashErase.h b/include/FlashErase.h
index cab4d7c..250c777 100644
--- a/include/FlashErase.h
+++ b/include/FlashErase.h
@@ -6,9 +6,8 @@
#ifndef FLASHERASE_H
#define FLASHERASE_H
-#include "Filesystem.h"
#include "MainBD.h"
-void doErase(mbed::BlockDevice &bd, LittleFileSystem2 &fs);
+void doErase(mbed::BlockDevice &bd);
#endif
diff --git a/include/MyUSBMSD.h b/include/MyUSBMSD.h
index 1ee05ce..51c7241 100644
--- a/include/MyUSBMSD.h
+++ b/include/MyUSBMSD.h
@@ -19,5 +19,5 @@
virtual const uint8_t *string_iproduct_desc();
};
-void doUSBMSD(mbed::BlockDevice &bd, LittleFileSystem2 &fs);
+void doUSBMSD(mbed::BlockDevice &bd);
#endif
diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp
index bc20282..8468ff6 100644
--- a/src/ButtonThread.cpp
+++ b/src/ButtonThread.cpp
@@ -9,7 +9,6 @@
EventFlags buttonFlags;
#define PUSH_FLAG 0b01
-#define LIFT_FLAG 0b10
void button_onrise(void) { buttonFlags.set(PUSH_FLAG); }
@@ -27,7 +26,7 @@
if (timed_out) {
break;
} else if (had_any_error) {
- error("Uhh what the f?\n");
+ error("Unable to wait for push button flag?\n");
} else {
pressed_count++;
}
diff --git a/src/Filesystem.cpp b/src/Filesystem.cpp
index 029423b..a580a81 100644
--- a/src/Filesystem.cpp
+++ b/src/Filesystem.cpp
@@ -15,7 +15,7 @@
// function to attempt to mount the filesystem and
// reformat and mount it again should it fail
-void mountFilesystem(mbed::BlockDevice &bd, LittleFileSystem2 &fs) {
+void mountFilesystem(mbed::BlockDevice &bd, mbed::FileSystem &fs) {
int err;
// Try to mount the filesystem
printf("Mounting the filesystem... ");
@@ -43,7 +43,7 @@
}
// function to unmount the filesystem
-void unmountFilesystem(mbed::BlockDevice &bd, LittleFileSystem2 &fs) {
+void unmountFilesystem(mbed::BlockDevice &bd, mbed::FileSystem &fs) {
// Try to unmount the filesystem
printf("Unmounting the filesystem... ");
fflush(stdout);
diff --git a/src/FlashErase.cpp b/src/FlashErase.cpp
index f772fd9..a84f71d 100644
--- a/src/FlashErase.cpp
+++ b/src/FlashErase.cpp
@@ -9,9 +9,7 @@
#include
// function to erase the flash
-void doErase(mbed::BlockDevice &bd, LittleFileSystem2 &fs) {
- // Try to unmount the filesystem
- unmountFilesystem(bd, fs);
+void doErase(mbed::BlockDevice &bd) {
printf("Initializing the block device... ");
fflush(stdout);
int err = bd.init();
diff --git a/src/MyUSBMSD.cpp b/src/MyUSBMSD.cpp
index 0b23a56..08d6bbc 100644
--- a/src/MyUSBMSD.cpp
+++ b/src/MyUSBMSD.cpp
@@ -5,7 +5,6 @@
#include "MyUSBMSD.h"
#include "ButtonThread.h"
-#include "Filesystem.h"
#include "mbed.h"
// create a custom usb mass storage subclass to override
@@ -26,9 +25,7 @@
return string_iproduct_descriptor;
}
-void doUSBMSD(mbed::BlockDevice &bd, LittleFileSystem2 &fs) {
- // Try to unmount the filesystem
- unmountFilesystem(bd, fs);
+void doUSBMSD(mbed::BlockDevice &bd) {
printf("Switching to the usb mass storage mode...\n");
MyUSBMSD usb(&bd, true, 0x1209, 0x10);
@@ -40,7 +37,6 @@
"device...\n");
usb.disconnect();
printf("Switched usb mass storage mode off.\n");
- mountFilesystem(bd, fs);
break;
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 2c834bb..5a3e748 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -4,34 +4,138 @@
Copyright (c) 2023 John Watts and the LuminaSensum contributors
*/
-#include "ButtonThread.h"
-#include "Filesystem.h"
-#include "FlashErase.h"
-#include "MainBD.h"
-#include "MainFilesystem.h"
-#include "MyUSBMSD.h"
#include "mbed.h"
-
-int main() {
- printf("Project Tardis\n");
-
- mountFilesystem(mainBD, mainFS);
-
- Thread buttonThread;
- buttonThread.start(buttonTask);
-
- while (true) {
- int presses = waitForPresses(600s);
- if (presses == 1) {
- doUSBMSD(mainBD, mainFS);
- }
-
- if (presses == 2) {
- doErase(mainBD, mainFS);
- }
- }
-
- buttonThread.terminate();
-
- return 0;
+#include "stm32f769i_discovery.h"
+#include "stm32f769i_discovery_audio.h"
+
+static void CopyBuffer(int16_t *pbuffer1, int16_t *pbuffer2, uint16_t BufferSize);
+
+#define SCRATCH_BUFF_SIZE 1024
+#define RECORD_BUFFER_SIZE 4096
+
+typedef enum {
+ BUFFER_OFFSET_NONE = 0,
+ BUFFER_OFFSET_HALF = 1,
+ BUFFER_OFFSET_FULL = 2,
+} BUFFER_StateTypeDef;
+
+volatile uint32_t audio_rec_buffer_state = BUFFER_OFFSET_NONE;
+int32_t Scratch[SCRATCH_BUFF_SIZE];
+
+/* Buffer containing the PCM samples coming from the microphone */
+int16_t RecordBuffer[RECORD_BUFFER_SIZE];
+
+/* Buffer used to stream the recorded PCM samples towards the audio codec. */
+int16_t PlaybackBuffer[RECORD_BUFFER_SIZE];
+
+int main()
+{
+ uint32_t audio_loop_back_init = RESET ;
+
+ printf("\n\nAUDIO LOOPBACK EXAMPLE FOR DISCO-F769NI START:\n");
+
+ /* Initialize Audio Recorder with 4 channels to be used */
+ if (BSP_AUDIO_IN_Init(BSP_AUDIO_FREQUENCY_44K, DEFAULT_AUDIO_IN_BIT_RESOLUTION, 2*DEFAULT_AUDIO_IN_CHANNEL_NBR) == AUDIO_ERROR) {
+ printf("BSP_AUDIO_IN_Init error\n");
+ }
+
+ /* Allocate scratch buffers */
+ if (BSP_AUDIO_IN_AllocScratch (Scratch, SCRATCH_BUFF_SIZE) == AUDIO_ERROR) {
+ printf("BSP_AUDIO_IN_AllocScratch error\n");
+ }
+
+ /* Start Recording */
+ if (BSP_AUDIO_IN_Record((uint16_t*)&RecordBuffer[0], RECORD_BUFFER_SIZE) == AUDIO_ERROR) {
+ printf("BSP_AUDIO_IN_Record error\n");
+ }
+ uint8_t ChannelNumber = BSP_AUDIO_IN_GetChannelNumber();
+
+ audio_rec_buffer_state = BUFFER_OFFSET_NONE;
+
+ while (1) {
+ /* 1st or 2nd half of the record buffer ready for being copied to the playbakc buffer */
+ if(audio_rec_buffer_state != BUFFER_OFFSET_NONE) {
+ /* Copy half of the record buffer to the playback buffer */
+ if(audio_rec_buffer_state == BUFFER_OFFSET_HALF) {
+ CopyBuffer(&PlaybackBuffer[0], &RecordBuffer[0], RECORD_BUFFER_SIZE/2);
+ if (audio_loop_back_init == RESET) {
+ /* Initialize the audio device*/
+ if (BSP_AUDIO_OUT_Init(OUTPUT_DEVICE_HEADPHONE, 70, BSP_AUDIO_FREQUENCY_44K) == AUDIO_ERROR) {
+ printf("BSP_AUDIO_OUT_Init error\n");
+ }
+ if(ChannelNumber > 2) {
+ BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_0123);
+ } else {
+ BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_02);
+ }
+
+ /* Play the recorded buffer */
+ if (BSP_AUDIO_OUT_Play((uint16_t *) &PlaybackBuffer[0], 2*RECORD_BUFFER_SIZE) == AUDIO_ERROR) {
+ printf("BSP_AUDIO_OUT_Play error\n");
+ }
+ /* Audio device is initialized only once */
+ audio_loop_back_init = SET;
+ }
+
+
+ } else { /* if(audio_rec_buffer_state == BUFFER_OFFSET_FULL)*/
+ CopyBuffer(&PlaybackBuffer[RECORD_BUFFER_SIZE/2], &RecordBuffer[RECORD_BUFFER_SIZE/2], RECORD_BUFFER_SIZE/2);
+ }
+
+ /* Wait for next data */
+ audio_rec_buffer_state = BUFFER_OFFSET_NONE;
+ }
+ }
+}
+
+/*-------------------------------------------------------------------------------------
+ Callbacks implementation:
+ the callbacks API are defined __weak in the stm32f769i_discovery_audio.c file
+ and their implementation should be done in the user code if they are needed.
+ Below some examples of callback implementations.
+ -------------------------------------------------------------------------------------*/
+/**
+ * @brief Manages the DMA Transfer complete interrupt.
+ * @param None
+ * @retval None
+ */
+void BSP_AUDIO_IN_TransferComplete_CallBack(void)
+{
+ audio_rec_buffer_state = BUFFER_OFFSET_FULL;
+}
+
+/**
+ * @brief Manages the DMA Half Transfer complete interrupt.
+ * @param None
+ * @retval None
+ */
+void BSP_AUDIO_IN_HalfTransfer_CallBack(void)
+{
+ audio_rec_buffer_state = BUFFER_OFFSET_HALF;
+}
+
+/**
+ * @brief Audio IN Error callback function.
+ * @param None
+ * @retval None
+ */
+void BSP_AUDIO_IN_Error_CallBack(void)
+{
+ printf("BSP_AUDIO_IN_Error_CallBack\n");
+}
+
+
+/**
+ * @brief Copy content of pbuffer2 to pbuffer1
+ * @param1 BufferOut
+ * @param2 BufferIn
+ * @param3 Size
+ * @retval None
+ */
+static void CopyBuffer(int16_t *pbuffer1, int16_t *pbuffer2, uint16_t BufferSize)
+{
+ uint32_t i = 0;
+ for(i = 0; i < BufferSize; i++) {
+ pbuffer1[i] = pbuffer2[i];
+ }
}