aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Utilities/STM32_EVAL/STM32303C_EVAL/stm32303c_eval_audio_codec.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Utilities/STM32_EVAL/STM32303C_EVAL/stm32303c_eval_audio_codec.c')
-rw-r--r--thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Utilities/STM32_EVAL/STM32303C_EVAL/stm32303c_eval_audio_codec.c1597
1 files changed, 1597 insertions, 0 deletions
diff --git a/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Utilities/STM32_EVAL/STM32303C_EVAL/stm32303c_eval_audio_codec.c b/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Utilities/STM32_EVAL/STM32303C_EVAL/stm32303c_eval_audio_codec.c
new file mode 100644
index 0000000..9d0991d
--- /dev/null
+++ b/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Utilities/STM32_EVAL/STM32303C_EVAL/stm32303c_eval_audio_codec.c
@@ -0,0 +1,1597 @@
+/**
+ ******************************************************************************
+ * @file stm32303c_eval_audio_codec.c
+ * @author MCD Application Team
+ * @version V1.0.1
+ * @date 23-October-2012
+ * @brief This file includes the low layer driver for CS42L52 Audio Codec
+ * available on STM32303C_EVAL evaluation board(MB1019).
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
+ *
+ * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.st.com/software_license_agreement_liberty_v2
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************
+ */
+
+/*==============================================================================================================================
+ User NOTES
+1. How To use this driver:
+--------------------------
+ - This driver supports STM32F30x devices on STM32303C_EVAL (MB1019) Evaluation boards.
+
+ - Configure the options in file stm32303c_eval_audio_codec.h in the section CONFIGURATION.
+ Refer to the sections 2 and 3 to have more details on the possible configurations.
+
+ - Call the function EVAL_AUDIO_Init(
+ OutputDevice: physical output mode (OUTPUT_DEVICE_SPEAKER,
+ OUTPUT_DEVICE_HEADPHONE, OUTPUT_DEVICE_AUTO 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, I2S,
+ GPIOs, DMA and interrupt if needed). This function returns 0 if configuration is OK.
+ if the returned value is different from 0 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_AUTO: Selection of output device is made through external switch (implemented
+ into the audio jack on the evaluation board). When the Headphone is connected it is used
+ as output. When the headphone is disconnected from the audio jack, the output is
+ automatically switched to Speaker.
+ + OUTPUT_DEVICE_BOTH: both Speaker and Headphone are used as outputs for the audio stream
+ at the same time.
+
+ - Call the function EVAL_AUDIO_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 EVAL_AUDIO_PauseResume(
+ Cmd: AUDIO_PAUSE (or 0) to pause playing or AUDIO_RESUME (or
+ any value different from 0) to resume playing.
+ )
+ Note. After calling EVAL_AUDIO_PauseResume() function for pause, only EVAL_AUDIO_PauseResume() should be called
+ for resume (it is not allowed to call EVAL_AUDIO_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 EVAL_AUDIO_XXX_CallBack() and only their prototypes are declared in
+ the stm32303c_eval_audio_codec.h file. (refer to the example for more details on the callbacks implementations)
+
+ - To Stop playing, to modify the volume level or to mute, use the functions
+ EVAL_AUDIO_Stop(), EVAL_AUDIO_VolumeCtl() and EVAL_AUDIO_Mute().
+
+ - The driver API and the callback functions are at the end of the stm32303c_eval_audio_codec.h file.
+
+
+ Driver architecture:
+ --------------------
+ This driver is composed of three main layers:
+ o High Audio Layer: consists of the function API exported in the stm32303c_eval_audio_codec.h file
+ (EVAL_AUDIO_Init(), EVAL_AUDIO_Play() ...)
+ o Codec Control layer: consists of the functions API controlling the audio codec (CS42L52) and
+ included as local functions in file stm32303c_eval_audio_codec.c (Codec_Init(), Codec_Play() ...)
+ o 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 stm32303c_eval_audio_codec.c file (Audio_MAL_Init(), Audio_MAL_Play() ...)
+ Each set of functions (layer) may be implemented independently of the others and customized when
+ needed.
+
+2. Modes description:
+---------------------
+ + AUDIO_MAL_MODE_NORMAL : is suitable when the audio file is in a memory location.
+ + AUDIO_MAL_MODE_CIRCULAR: is suitable when the audio data are read either from a
+ memory location or from a device at real time (double buffer could be used).
+
+3. DMA interrupts description:
+------------------------------
+ + EVAL_AUDIO_IT_TC_ENABLE: Enable this define to use the DMA end of transfer interrupt.
+ then, a callback should be implemented by user to perform specific actions
+ when the DMA has finished the transfer.
+ + EVAL_AUDIO_IT_HT_ENABLE: Enable this define to use the DMA end of half transfer interrupt.
+ then, a callback should be implemented by user to perform specific actions
+ when the DMA has reached the half of the buffer transfer (generally, it is useful
+ to load the first half of buffer while DMA is loading from the second half).
+ + EVAL_AUDIO_IT_ER_ENABLE: Enable this define to manage the cases of error on DMA transfer.
+
+4. Known Limitations:
+---------------------
+ 1- When using the Speaker, if the audio file quality is not high enough, the speaker output
+ may produce high and uncomfortable noise level. To avoid this issue, to use speaker
+ output properly, try to increase audio file sampling rate (typically higher than 48KHz).
+ This operation will lead to larger file size.
+ 2- Communication with the audio codec (through I2C) may be corrupted if it is interrupted by some
+ user interrupt routines (in this case, interrupts could be disabled just before the start of
+ communication then re-enabled when it is over). Note that this communication is only done at
+ the configuration phase (EVAL_AUDIO_Init() or EVAL_AUDIO_Stop()) and when Volume control modification is
+ performed (EVAL_AUDIO_VolumeCtl() or EVAL_AUDIO_Mute()). When the audio data is played, no communication is
+ required with the audio codec.
+ 3- 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.
+ 4- Mono audio streaming is not supported (in order to play mono audio streams, each data should be sent twice
+ on the I2S or should be duplicated on the source buffer. Or convert the stream in stereo before playing).
+ 5- Supports only 16-bit audio data size.
+===============================================================================================================================*/
+
+
+/* Includes ------------------------------------------------------------------*/
+#include "stm32303c_eval_audio_codec.h"
+
+/** @addtogroup Utilities
+ * @{
+ */
+
+/** @addtogroup STM32_EVAL
+ * @{
+ */
+
+/** @addtogroup STM32303C_EVAL
+ * @{
+ */
+
+/** @addtogroup STM32303C_EVAL_AUDIO_CODEC
+ * @brief This file includes the low layer driver for CS42L52 Audio Codec
+ * available on STM32303C_EVAL evaluation board(MB1019).
+ * @{
+ */
+
+/** @defgroup STM32303C_EVAL_AUDIO_CODEC_Private_Types
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32303C_EVAL_AUDIO_CODEC_Private_Defines
+ * @{
+ */
+
+/* Mask for the bit EN of the I2S CFGR register */
+#define I2S_ENABLE_MASK 0x0400
+
+/* Delay for the Codec to be correctly reset */
+#define CODEC_RESET_DELAY 0x4FFF
+
+/* Codec audio Standards */
+#ifdef I2S_STANDARD_PHILLIPS
+ #define CODEC_STANDARD 0x04
+ #define I2S_STANDARD I2S_Standard_Phillips
+#elif defined(I2S_STANDARD_MSB)
+ #define CODEC_STANDARD 0x00
+ #define I2S_STANDARD I2S_Standard_MSB
+#elif defined(I2S_STANDARD_LSB)
+ #define CODEC_STANDARD 0x08
+ #define I2S_STANDARD I2S_Standard_LSB
+#else
+ #error "Error: No audio communication standard selected !"
+#endif /* I2S_STANDARD */
+
+/* The 7 bits Codec address (sent through I2C interface) */
+#define CODEC_ADDRESS 0x94 /* b1001010. */
+/**
+ * @}
+ */
+
+/** @defgroup STM32303C_EVAL_AUDIO_CODEC_Private_Macros
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32303C_EVAL_AUDIO_CODEC_Private_Variables
+ * @{
+ */
+/* This structure is declared global because it is handled by two different functions */
+DMA_InitTypeDef DMA_InitStructure;
+DMA_InitTypeDef AUDIO_MAL_DMA_InitStructure;
+
+uint32_t AudioTotalSize = 0xFFFF; /* This variable holds the total size of the audio file */
+uint32_t AudioRemSize = 0xFFFF; /* This variable holds the remaining data in audio file */
+uint16_t *CurrentPos; /* This variable holds the current position of audio pointer */
+
+__IO uint32_t CODECTimeout = CODEC_LONG_TIMEOUT;
+__IO uint8_t OutputDev = 0;
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32303C_EVAL_AUDIO_CODEC_Private_Function_Prototypes
+ * @{
+ */
+/**
+ * @}
+ */
+
+/** @defgroup STM32303C_EVAL_AUDIO_CODEC_Private_Functions
+ * @{
+ */
+
+/*----------------------------------------------------------------------------
+ Audio Codec functions
+ ----------------------------------------------------------------------------*/
+/* High Layer codec functions */
+static uint32_t Codec_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq);
+static uint32_t Codec_DeInit(void);
+static uint32_t Codec_Play(void);
+static uint32_t Codec_PauseResume(uint32_t Cmd);
+static uint32_t Codec_Stop(uint32_t Cmd);
+static uint32_t Codec_VolumeCtrl(uint8_t Volume);
+static uint32_t Codec_Mute(uint32_t Cmd);
+/* Low layer codec functions */
+static void Codec_CtrlInterface_Init(void);
+static void Codec_CtrlInterface_DeInit(void);
+static void Codec_AudioInterface_Init(uint32_t AudioFreq);
+static void Codec_AudioInterface_DeInit(void);
+uint32_t Codec_ReadRegister(uint8_t RegisterAddr);
+static void Codec_GPIO_Init(void);
+static void Codec_GPIO_Recorder_Init(void);
+static void Codec_GPIO_DeInit(void);
+static void Delay(__IO uint32_t nCount);
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ MAL (Media Access Layer) functions
+ ----------------------------------------------------------------------------*/
+/* Peripherals configuration functions */
+static void Audio_MAL_Init(void);
+static void Audio_MAL_DeInit(void);
+static void Audio_MAL_PauseResume(uint32_t Cmd, uint32_t Addr);
+static void Audio_MAL_Stop(void);
+/*----------------------------------------------------------------------------*/
+
+/**
+ * @brief Configure the audio peripherals.
+ * @param OutputDevice: OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
+ * OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO .
+ * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max))
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t EVAL_AUDIO_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq)
+{
+ /* Perform low layer Codec initialization */
+ if (Codec_Init(OutputDevice, VOLUME_CONVERT(Volume), AudioFreq) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ /* I2S data transfer preparation:
+ Prepare the Media to be used for the audio transfer from memory to I2S peripheral */
+ Audio_MAL_Init();
+
+ /* Return 0 when all operations are OK */
+ return 0;
+ }
+}
+
+/**
+ * @brief Deinitializes all the resources used by the codec (those initialized
+ * by EVAL_AUDIO_Init() function).
+ * @param None
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t EVAL_AUDIO_DeInit(void)
+{
+ /* DeInitialize Codec */
+ Codec_DeInit();
+
+ /* DeInitialize the Media layer */
+ Audio_MAL_DeInit();
+
+ return 0;
+}
+
+/**
+ * @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 0 if correct communication, else wrong communication
+ */
+uint32_t EVAL_AUDIO_Play(uint16_t* pBuffer, uint32_t Size)
+{
+ /* Set the total number of data to be played (count in half-word) */
+ AudioTotalSize = Size/2;
+
+ /* Call the audio Codec Play function */
+ Codec_Play();
+
+ /* Update the Media layer and enable it for play */
+ Audio_MAL_Play((uint32_t)pBuffer, (uint32_t)(DMA_MAX(AudioTotalSize / 2)));
+
+ /* Update the remaining number of data to be played */
+ AudioRemSize = (Size/2) - DMA_MAX(AudioTotalSize);
+
+ /* Update the current audio pointer position */
+ CurrentPos = pBuffer + DMA_MAX(AudioTotalSize);
+
+ return 0;
+}
+
+/**
+ * @brief This function Pauses or Resumes the audio file stream. In case
+ * of using DMA, the DMA Pause feature is used. In all cases the I2S
+ * peripheral is disabled.
+ *
+ * @WARNING When calling EVAL_AUDIO_PauseResume() function for pause, only
+ * this function should be called for resume (use of EVAL_AUDIO_Play()
+ * function for resume could lead to unexpected behavior).
+ *
+ * @param Cmd: AUDIO_PAUSE (or 0) to pause, AUDIO_RESUME (or any value different
+ * from 0) to resume.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t EVAL_AUDIO_PauseResume(uint32_t Cmd)
+{
+ /* Call the Audio Codec Pause/Resume function */
+ if (Codec_PauseResume(Cmd) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ /* Call the Media layer pause/resume function */
+ Audio_MAL_PauseResume(Cmd, 0);
+
+ /* Return 0 if all operations are OK */
+ return 0;
+ }
+}
+
+/**
+ * @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 0 if correct communication, else wrong communication
+ */
+uint32_t EVAL_AUDIO_Stop(uint32_t Option)
+{
+ /* Call Audio Codec Stop function */
+ if (Codec_Stop(Option) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ /* Call Media layer Stop function */
+ Audio_MAL_Stop();
+
+ /* Update the remaining data number */
+ AudioRemSize = AudioTotalSize;
+
+ /* Return 0 when all operations are correctly done */
+ return 0;
+ }
+}
+
+/**
+ * @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 0 if correct communication, else wrong communication
+ */
+uint32_t EVAL_AUDIO_VolumeCtl(uint8_t Volume)
+{
+ /* Call the codec volume control function with converted volume value */
+ return (Codec_VolumeCtrl(VOLUME_CONVERT(Volume)));
+}
+
+/**
+ * @brief Enables or disables the MUTE mode by software
+ * @param Command: could be AUDIO_MUTE_ON to mute sound or AUDIO_MUTE_OFF to
+ * unmute the codec and restore previous volume level.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t EVAL_AUDIO_Mute(uint32_t Cmd)
+{
+ /* Call the Codec Mute function */
+ return (Codec_Mute(Cmd));
+}
+
+/**
+ * @brief This function handles main Media layer interrupt.
+ * @param None
+ * @retval 0 if correct communication, else wrong communication
+ */
+void Audio_MAL_IRQHandler(void)
+{
+#ifndef AUDIO_MAL_MODE_NORMAL
+ uint16_t *pAddr = (uint16_t *)CurrentPos;
+ uint32_t Size = AudioRemSize;
+#endif /* AUDIO_MAL_MODE_NORMAL */
+
+#ifdef AUDIO_MAL_DMA_IT_TC_EN
+ /* Transfer complete interrupt */
+ if (DMA_GetFlagStatus(AUDIO_MAL_DMA_FLAG_TC) != RESET)
+ {
+ #ifdef AUDIO_MAL_MODE_NORMAL
+ /* Check if the end of file has been reached */
+ if (AudioRemSize > 0)
+ {
+ /* Wait the DMA Channel to be effectively disabled */
+ while (DMA_GetFlagStatus(AUDIO_MAL_DMA_FLAG_TC) != SET)
+ {}
+
+ /* Clear the Interrupt flag */
+ DMA_ClearFlag(AUDIO_MAL_DMA_FLAG_TC);
+
+ /* Re-Configure the buffer address and size */
+ DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) CurrentPos;
+ DMA_InitStructure.DMA_BufferSize = (uint32_t) (DMA_MAX(AudioRemSize));
+
+ /* Configure the DMA Channel with the new parameters */
+ DMA_Init(AUDIO_MAL_DMA_CHANNEL , &DMA_InitStructure);
+
+ /* Enable the I2S DMA Channel */
+ DMA_Cmd(AUDIO_MAL_DMA_CHANNEL , ENABLE);
+
+ /* Update the current pointer position */
+ CurrentPos += DMA_MAX(AudioRemSize);
+
+ /* Update the remaining number of data to be played */
+ AudioRemSize -= DMA_MAX(AudioRemSize);
+ }
+ else
+ {
+ /* Disable the I2S DMA Channel */
+ DMA_Cmd(AUDIO_MAL_DMA_CHANNEL , DISABLE);
+
+ /* Clear the Interrupt flag */
+ DMA_ClearFlag(AUDIO_MAL_DMA_FLAG_TC);
+
+ /* Manage the remaining file size and new address offset: This function
+ should be coded by user (its prototype is already declared in stm32_eval_audio_codec.h) */
+ EVAL_AUDIO_TransferComplete_CallBack((uint32_t)CurrentPos, 0);
+ }
+
+ #elif defined(AUDIO_MAL_MODE_CIRCULAR)
+ /* Manage the remaining file size and new address offset: This function
+ should be coded by user (its prototype is already declared in stm32_eval_audio_codec.h) */
+ EVAL_AUDIO_TransferComplete_CallBack(pAddr, Size);
+
+ /* Clear the Interrupt flag */
+ DMA_ClearFlag(AUDIO_MAL_DMA_STREAM, AUDIO_MAL_DMA_FLAG_TC);
+ #endif /* AUDIO_MAL_MODE_NORMAL */
+ }
+#endif /* AUDIO_MAL_DMA_IT_TC_EN */
+
+#ifdef AUDIO_MAL_DMA_IT_HT_EN
+ /* Half Transfer complete interrupt */
+ if (DMA_GetFlagStatus(AUDIO_MAL_DMA_CHANNEL, AUDIO_MAL_DMA_FLAG_HT) != RESET)
+ {
+ /* Manage the remaining file size and new address offset: This function
+ should be coded by user (its prototype is already declared in stm32_eval_audio_codec.h) */
+ EVAL_AUDIO_HalfTransfer_CallBack((uint32_t)pAddr, Size);
+
+ /* Clear the Interrupt flag */
+ DMA_ClearFlag(AUDIO_MAL_DMA_CHANNEL, AUDIO_MAL_DMA_FLAG_HT);
+ }
+#endif /* AUDIO_MAL_DMA_IT_HT_EN */
+
+#ifdef AUDIO_MAL_DMA_IT_TE_EN
+ /* FIFO Error interrupt */
+ if ((DMA_GetFlagStatus(AUDIO_MAL_DMA_CHANNEL, AUDIO_MAL_DMA_FLAG_TE) != RESET) || \
+ (DMA_GetFlagStatus(AUDIO_MAL_DMA_CHANNEL, AUDIO_MAL_DMA_FLAG_FE) != RESET) || \
+ (DMA_GetFlagStatus(AUDIO_MAL_DMA_CHANNEL, AUDIO_MAL_DMA_FLAG_DME) != RESET))
+
+ {
+ /* Manage the error generated on DMA FIFO: This function
+ should be coded by user (its prototype is already declared in stm32_eval_audio_codec.h) */
+ EVAL_AUDIO_Error_CallBack((uint32_t*)&pAddr);
+
+ /* Clear the Interrupt flag */
+ DMA_ClearFlag(AUDIO_MAL_DMA_CHANNEL, AUDIO_MAL_DMA_FLAG_TE | AUDIO_MAL_DMA_FLAG_FE | \
+ AUDIO_MAL_DMA_FLAG_DME);
+ }
+#endif /* AUDIO_MAL_DMA_IT_TE_EN */
+}
+
+/*============================================================================
+ CS42L52 Audio Codec Control Functions
+ ============================================================================*/
+/**
+ * @brief Initializes the audio codec and all related interfaces (control
+ * interface: I2C and audio interface: I2S)
+ * @param OutputDevice: can be OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
+ * OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO .
+ * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max))
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @retval 0 if correct communication, else wrong communication
+ */
+static uint32_t Codec_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq)
+{
+ uint32_t counter = 0;
+
+ /* Configure the Codec related IOs */
+ Codec_GPIO_Init();
+
+ /* Initialize the Control interface of the Audio Codec */
+ Codec_CtrlInterface_Init();
+
+ /* Keep Codec powered OFF */
+ counter += Codec_WriteRegister(0x02, 0x9E/*0x01*/);
+
+ switch (OutputDevice)
+ {
+ case OUTPUT_DEVICE_SPEAKER:
+ counter += Codec_WriteRegister(0x04, 0xFA); /* SPK always ON & HP always OFF */
+ OutputDev = 0xFA;
+ break;
+
+ case OUTPUT_DEVICE_HEADPHONE:
+ counter += Codec_WriteRegister(0x04, 0xAF); /* SPK always OFF & HP always ON */
+ OutputDev = 0xAF;
+ break;
+
+ case OUTPUT_DEVICE_BOTH:
+ counter += Codec_WriteRegister(0x04, 0xAA); /* SPK always ON & HP always ON */
+ OutputDev = 0xAA;
+ break;
+
+ case OUTPUT_DEVICE_AUTO:
+ counter += Codec_WriteRegister(0x04, 0x05); /* Detect the HP or the SPK automatically */
+ OutputDev = 0x05;
+ break;
+
+ default:
+ counter += Codec_WriteRegister(0x04, 0x05); /* Detect the HP or the SPK automatically */
+ OutputDev = 0x05;
+ break;
+ }
+
+ /* Clock configuration: Auto detection */
+ counter += Codec_WriteRegister(0x05, 0x80);
+ /* Set the Slave Mode and the audio Standard */
+ counter += Codec_WriteRegister(0x06, 0x03/*CODEC_STANDARD*/);
+ /* Interface Control 2: SCLK is Re-timed signal from MCLK*/
+ counter +=Codec_WriteRegister(0x07, 0x00);
+ /* ADCA and PGAA Select: no input selected*/
+ counter +=Codec_WriteRegister(0x08, 0x00);
+ /* ADCB and PGAB Select: no input selected*/
+ counter +=Codec_WriteRegister(0x09, 0x00);
+ /*Play Back Control 1: headphone gain is 0.4, PCM not inverted, Master not mute*/
+ counter +=Codec_WriteRegister(0x0D, 0x10);/* CS42L52 has different config than CS42L52*/
+ /* Miscellaneous Controls: Passthrough Analog & Passthrough Mute off, Soft Ramp on @0x0E*/
+ counter +=Codec_WriteRegister(0x0E, 0x02);
+ /* Play Back Control 2: Headphone Mute off, speaker mute off, mono enabled */
+ counter +=Codec_WriteRegister(0x0F, 0x32);
+ /* PCM A Volume: PCM Mute disabled, Volume is 0db(default) */
+ counter +=Codec_WriteRegister(0x1A, 0x00);
+ /* PCM B Volume: PCM Mute disabled, Volume is 0db(default) */
+ counter +=Codec_WriteRegister(0x1B, 0x00);
+ /* Headphone A Volume: Headphone Volume is -6db */
+ counter +=Codec_WriteRegister(0x22, (u8)(0-12));
+ /* Headphone B Volume: Headphone Volume is -6db */
+ counter +=Codec_WriteRegister(0x23, (u8)(0-12));
+ /* Speaker A Volume: Speaker Volume is 0db (default) */
+ counter +=Codec_WriteRegister(0x24, 0x00);
+ /* Speaker B Volume: Speaker Volume is 0db (default) */
+ counter +=Codec_WriteRegister(0x25, 0x00);
+ /* Charge Pump Frequency: 5 (default) */
+ counter +=Codec_WriteRegister(0x34, 5<<4);
+ /* Power Control 1: power up */
+ counter += Codec_WriteRegister(0x02, 0x00);
+ counter += Codec_WriteRegister(0x20, 0xff);
+ counter += Codec_WriteRegister(0x21, 0xff);
+
+ /* Configure the I2S peripheral */
+ Codec_AudioInterface_Init(AudioFreq);
+
+ /* Return communication control value */
+ return counter;
+}
+
+/**
+ * @brief Initializes the audio codec and all related interfaces (control
+ * interface: I2C and audio interface: I2S)
+ * @param OutputDevice: can be OUTPUT_DEVICE_SPEAKER, OUTPUT_DEVICE_HEADPHONE,
+ * OUTPUT_DEVICE_BOTH or OUTPUT_DEVICE_AUTO .
+ * @param Volume: Initial volume level (from 0 (Mute) to 100 (Max))
+ * @param AudioFreq: Audio frequency used to play the audio stream.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t Codec_Record_Init(void)
+{
+ uint32_t counter = 0;
+
+ /* Configure the Codec related IOs */
+ Codec_GPIO_Recorder_Init();
+
+ /* Initialize the Control interface of the Audio Codec */
+ Codec_CtrlInterface_Init();
+
+ /* Mono Record @ MIC1+ with Bias */
+ /* Power Control 2[@03h]: MICB Off, MIC A & Bias On */
+ counter += Codec_WriteRegister(0x03, 0x04);
+ /* Power Control 3[@04h]: headphone A/B Off, speaker A & B Off */
+ counter += Codec_WriteRegister(0x04, 0xFF);
+ /* Clocking Control: auto sample rate(Fs) */
+ counter += Codec_WriteRegister(0x05, 0x80);
+ /* Interface Control 1: slave, LeftJustified, 16-bit data */
+ counter += Codec_WriteRegister(0x06, 0x03);
+ /* Interface Control 2: SCLK is Re-timed signal from MCLK, BIAS: 0.5*VA */
+ counter += Codec_WriteRegister(0x07, 0x00);
+ /* ADCA and PGAA Select: MICx selected */
+ counter += Codec_WriteRegister(0x08, 0x90);
+ /* ADCB and PGAB Select: MICx selected */
+ counter += Codec_WriteRegister(0x09, 0x90);
+ /* Misc ADC Control: SDOUT Signal Source is ADC_or_DSP */
+ counter += Codec_WriteRegister(0x0C, 0x00);
+ /* Play Back Control 1: headphone gain is 0.4, PCM not inverted, Master not mute */
+ counter += Codec_WriteRegister(0x0D, 0x00);
+ /* Miscellaneous Controls: Passthrough Analog & Passthrough Mute off, Soft Ramp on @0x0E */
+ counter += Codec_WriteRegister(0x0E, 0x02);
+ /* Play Back Control 2: Headphone Mute on, speaker mute off, mono enabled */
+ counter += Codec_WriteRegister(0x0F, 0xC2);
+ /* MICA Amp Control: select MIC 2x, Single-Ended, Gain=16db */
+ counter += Codec_WriteRegister(0x10, 0x2E);
+ /* MICB Amp Control: select MIC 2x, Single-Ended, Gain=16db */
+ counter += Codec_WriteRegister(0x11, 0x40);
+ /* MICB Amp Control: try with Differential, Gain=16db */
+ counter += Codec_WriteRegister(0x11, 0x20);
+ /* PGA Volume ALC Control: Gain=0db */
+ counter += Codec_WriteRegister(0x12, 0x00);
+ /* PGA Volume ALC Control: Gain=0db */
+ counter += Codec_WriteRegister(0x13, 0x00);
+ counter += Codec_WriteRegister(0x34, 5<<4);
+
+ counter += Codec_WriteRegister(0x02, 0x14);
+
+ /* Return communication control value */
+ return counter;
+
+}
+
+/**
+ * @brief Restore the audio codec state to default state and free all used
+ * resources.
+ * @param None
+ * @retval 0 if correct communication, else wrong communication
+ */
+static uint32_t Codec_DeInit(void)
+{
+ uint32_t counter = 0;
+ uint16_t i = 0;
+ uint8_t tmp = 0;
+
+ /* Enable Master Playback Mute @0x0D */
+ counter += Codec_WriteRegister(0x02, 0x03);
+ /* Power down CS42L52 @0x03 */
+ counter += Codec_WriteRegister(0x03, 0x07);
+ /* Power down CS42L52 @0x04 */
+ counter += Codec_WriteRegister(0x04, 0xFF);
+ /* config interface @0x06 */
+ counter += Codec_WriteRegister(0x06, 0x03);
+ /* Disable Analog (Soft Ramp & Zero Cross) and HighPassFilter @0x0A */
+ counter += Codec_WriteRegister(0x0A, 0x00);
+ /* Digital Soft Ramp on & Zero Cross off @0x0E */
+ counter += Codec_WriteRegister(0x0E, 0x02);
+ /* Headphone Mute, Speaker Mute @0x0F */
+ counter += Codec_WriteRegister(0x0F, 0xF2);
+ /* PCM A Volume: Mute @0x1A */
+ counter += Codec_WriteRegister(0x1A, 0x80);
+ /* PCM B Volume: Mute @0x1B */
+ counter += Codec_WriteRegister(0x1B, 0x80);
+ /* Limiter Attack Rate: 0x00 @0x29 */
+ counter += Codec_WriteRegister(0x29, 0x00);
+
+ i = 0;
+ do{
+ // Power down CS42L52 @0x02
+ counter += Codec_WriteRegister(0x02, 0x9F);
+ tmp = Codec_ReadRegister(0x02);
+ i++;
+ }
+ while (((tmp & 0x01) == 0) && (i < 10));
+
+ Delay(CODEC_RESET_DELAY);
+
+ /* Deinitialize all use GPIOs */
+ Codec_GPIO_DeInit();
+
+ /* Deinitialize the Codec audio interface (I2S) */
+ Codec_AudioInterface_DeInit();
+ /* Disable the Codec control interface */
+ Codec_CtrlInterface_DeInit();
+
+ /* Return communication control value */
+ return counter;
+}
+
+/**
+ * @brief Start the audio Codec play feature.
+ * @note For this codec no Play options are required.
+ * @param None
+ * @retval 0 if correct communication, else wrong communication
+ */
+static uint32_t Codec_Play(void)
+{
+ /*
+ No actions required on Codec level for play command
+ */
+
+ /* Return communication control value */
+ return 0;
+}
+
+/**
+ * @brief Pauses and resumes playing on the audio codec.
+ * @param Cmd: AUDIO_PAUSE (or 0) to pause, AUDIO_RESUME (or any value different
+ * from 0) to resume.
+ * @retval 0 if correct communication, else wrong communication
+ */
+static uint32_t Codec_PauseResume(uint32_t Cmd)
+{
+ uint32_t counter = 0;
+
+ /* Pause the audio file playing */
+ if (Cmd == AUDIO_PAUSE)
+ {
+ /* Mute the output first */
+ counter += Codec_Mute(AUDIO_MUTE_ON);
+
+ /* Put the Codec in Power save mode */
+ counter += Codec_WriteRegister(0x02, 0x01);
+ }
+ else /* AUDIO_RESUME */
+ {
+ /* Unmute the output first */
+ counter += Codec_Mute(AUDIO_MUTE_OFF);
+
+ counter += Codec_WriteRegister(0x04, OutputDev);
+
+ /* Exit the Power save mode */
+ counter += Codec_WriteRegister(0x02, 0x9E);
+
+ }
+
+ return counter;
+}
+
+/**
+ * @brief Stops audio Codec playing. It powers down the codec.
+ * @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
+ */
+static uint32_t Codec_Stop(uint32_t CodecPdwnMode)
+{
+ uint32_t counter = 0;
+
+ /* Mute the output first */
+ Codec_Mute(AUDIO_MUTE_ON);
+
+ if (CodecPdwnMode == CODEC_PDWN_SW)
+ {
+ /* Power down the DAC and the speaker (PMDAC and PMSPK bits)*/
+ counter += Codec_WriteRegister(0x02, 0x9F);
+ }
+ else /* CODEC_PDWN_HW */
+ {
+ /* Power down the components */
+ counter += Codec_WriteRegister(0x02, 0x9F);
+
+ /* Wait at least 100us */
+ Delay(0xFFF);
+ }
+ return counter;
+}
+
+/**
+ * @brief Sets higher or lower the codec volume level.
+ * @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
+ */
+static uint32_t Codec_VolumeCtrl(uint8_t Volume)
+{
+ uint32_t counter = 0;
+
+ if (Volume > 0xE6)
+ {
+ /* Set the Master volume */
+ counter += Codec_WriteRegister(0x20, Volume - 0xE7);
+ counter += Codec_WriteRegister(0x21, Volume - 0xE7);
+ }
+ else
+ {
+ /* Set the Master volume */
+ counter += Codec_WriteRegister(0x20, Volume + 0x19);
+ counter += Codec_WriteRegister(0x21, Volume + 0x19);
+ }
+
+ return counter;
+}
+
+/**
+ * @brief Enables or disables the mute feature on the audio codec.
+ * @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
+ */
+static uint32_t Codec_Mute(uint32_t Cmd)
+{
+ uint32_t counter = 0;
+
+ /* Set the Mute mode */
+ if (Cmd == AUDIO_MUTE_ON)
+ {
+ counter += Codec_WriteRegister(0x04, 0xFF);
+ counter += Codec_WriteRegister(0x0F, 0xF0);
+ }
+ else /* AUDIO_MUTE_OFF Disable the Mute */
+ {
+ counter += Codec_WriteRegister(0x04, 0x05);
+ counter += Codec_WriteRegister(0x0F, 0x02);
+ }
+
+ return counter;
+}
+
+/**
+ * @brief Switch dynamically (while audio file is played) the output target
+ * (speaker or headphone).
+ * @note This function modifies a global variable of the audio codec driver: OutputDev.
+ * @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 Codec_SwitchOutput(uint8_t Output)
+{
+ uint8_t counter = 0;
+
+ switch (Output)
+ {
+ case OUTPUT_DEVICE_SPEAKER:
+ counter += Codec_WriteRegister(0x04, 0xFA); /* SPK always ON & HP always OFF */
+ OutputDev = 0xFA;
+ break;
+
+ case OUTPUT_DEVICE_HEADPHONE:
+ counter += Codec_WriteRegister(0x04, 0xAF); /* SPK always OFF & HP always ON */
+ OutputDev = 0xAF;
+ break;
+
+ case OUTPUT_DEVICE_BOTH:
+ counter += Codec_WriteRegister(0x04, 0xAA); /* SPK always ON & HP always ON */
+ OutputDev = 0xAA;
+ break;
+
+ case OUTPUT_DEVICE_AUTO:
+ counter += Codec_WriteRegister(0x04, 0x05); /* Detect the HP or the SPK automatically */
+ OutputDev = 0x05;
+ break;
+
+ default:
+ counter += Codec_WriteRegister(0x04, 0x05); /* Detect the HP or the SPK automatically */
+ OutputDev = 0x05;
+ break;
+ }
+
+ return counter;
+}
+
+/**
+ * @brief Writes a Byte to a given register into the audio codec through the
+ control interface (I2C)
+ * @param RegisterAddr: The address (location) of the register to be written.
+ * @param RegisterValue: the Byte value to be written into destination register.
+ * @retval 0 if correct communication, else wrong communication
+ */
+uint32_t Codec_WriteRegister(uint8_t RegisterAddr, uint8_t RegisterValue)
+{
+ uint32_t result = 0;
+
+ /* Test on BUSY Flag */
+ CODECTimeout = CODEC_FLAG_TIMEOUT;
+ while(I2C_GetFlagStatus(CODEC_I2C, I2C_ISR_BUSY) != RESET)
+ {
+ if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback();
+ }
+
+ /* Configure slave address, nbytes, reload, end mode and start or stop generation */
+ I2C_TransferHandling(CODEC_I2C, CODEC_ADDRESS, 2, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);
+
+ /* Wait until TXIS flag is set */
+ CODECTimeout = CODEC_FLAG_TIMEOUT;
+ while(I2C_GetFlagStatus(CODEC_I2C, I2C_ISR_TXIS) == RESET)
+ {
+ if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback();
+ }
+
+ /* Send Register address */
+ I2C_SendData(CODEC_I2C, (uint8_t)RegisterAddr );
+
+ /* Wait until TXIS flag is set */
+ CODECTimeout = CODEC_FLAG_TIMEOUT;
+ while(I2C_GetFlagStatus(CODEC_I2C, I2C_ISR_TXIS) == RESET)
+ {
+ if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback();
+ }
+
+ /* Write data to TXDR */
+ I2C_SendData(CODEC_I2C, (uint8_t)RegisterValue);
+
+ /* Wait until STOPF flag is set */
+ CODECTimeout = CODEC_FLAG_TIMEOUT;
+ while(I2C_GetFlagStatus(CODEC_I2C, I2C_ISR_STOPF) == RESET)
+ {
+ if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback();
+ }
+
+ /* Clear STOPF flag */
+ I2C_ClearFlag(CODEC_I2C, I2C_ICR_STOPCF);
+
+#ifdef VERIFY_WRITTENDATA
+ /* Verify that the data has been correctly written */
+ result = (Codec_ReadRegister(RegisterAddr) == RegisterValue)? 0:1;
+#endif /* VERIFY_WRITTENDATA */
+
+ /* Return the verifying value: 0 (Passed) or 1 (Failed) */
+ return result;
+}
+
+/**
+ * @brief Reads and returns the value of an audio codec register through the
+ * control interface (I2C).
+ * @param RegisterAddr: Address of the register to be read.
+ * @retval Value of the register to be read or dummy value if the communication
+ * fails.
+ */
+uint32_t Codec_ReadRegister(uint8_t RegisterAddr)
+{
+ uint32_t result = 0;
+
+ /* Test on BUSY Flag */
+ CODECTimeout = CODEC_LONG_TIMEOUT;
+ while(I2C_GetFlagStatus(CODEC_I2C, I2C_ISR_BUSY) != RESET)
+ {
+ if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback();
+ }
+
+ /* Configure slave address, nbytes, reload, end mode and start or stop generation */
+ I2C_TransferHandling(CODEC_I2C, CODEC_ADDRESS, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
+
+ /* Wait until TXIS flag is set */
+ CODECTimeout = CODEC_LONG_TIMEOUT;
+ while(I2C_GetFlagStatus(CODEC_I2C, I2C_ISR_TXIS) == RESET)
+ {
+ if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback();
+ }
+
+ /* Send Register address */
+ I2C_SendData(CODEC_I2C, (uint8_t)RegisterAddr);
+
+ /* Wait until TC flag is set */
+ CODECTimeout = CODEC_LONG_TIMEOUT;
+ while(I2C_GetFlagStatus(CODEC_I2C, I2C_ISR_TC) == RESET)
+ {
+ if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback();
+ }
+
+ /* Configure slave address, nbytes, reload, end mode and start or stop generation */
+ I2C_TransferHandling(CODEC_I2C, CODEC_ADDRESS, 1, I2C_AutoEnd_Mode, I2C_Generate_Start_Read);
+
+ /* Wait until RXNE flag is set */
+ CODECTimeout = CODEC_LONG_TIMEOUT;
+ while(I2C_GetFlagStatus(CODEC_I2C, I2C_ISR_RXNE) == RESET)
+ {
+ if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback();
+ }
+
+ /* Read data from RXDR */
+ result = I2C_ReceiveData(CODEC_I2C);
+
+ /* Wait until STOPF flag is set */
+ CODECTimeout = CODEC_LONG_TIMEOUT;
+ while(I2C_GetFlagStatus(CODEC_I2C, I2C_ISR_STOPF) == RESET)
+ {
+ if((CODECTimeout--) == 0) return Codec_TIMEOUT_UserCallback();
+ }
+
+ /* Clear STOPF flag */
+ I2C_ClearFlag(CODEC_I2C, I2C_ICR_STOPCF);
+
+ /* Return the byte read from Codec */
+ return result;
+}
+
+/**
+ * @brief Initializes the Audio Codec control interface (I2C).
+ * @param None
+ * @retval None
+ */
+static void Codec_CtrlInterface_Init(void)
+{
+ I2C_InitTypeDef I2C_InitStructure;
+
+ /* Configure the I2C clock source. The clock is derived from the SYSCLK */
+ RCC_I2CCLKConfig(RCC_I2C2CLK_SYSCLK);
+
+ /* Enable the CODEC_I2C peripheral clock */
+ RCC_APB1PeriphClockCmd(CODEC_I2C_CLK, ENABLE);
+
+ /* CODEC_I2C configuration */
+ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
+ I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
+ I2C_InitStructure.I2C_DigitalFilter = 0x00;
+ I2C_InitStructure.I2C_OwnAddress1 = 0x00;
+ I2C_InitStructure.I2C_Ack = I2C_Ack_Disable;
+ I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
+ I2C_InitStructure.I2C_Timing = CODEC_I2C_TIMING;
+
+ /* Enable the I2C peripheral */
+ I2C_Init(CODEC_I2C, &I2C_InitStructure);
+ I2C_Cmd(CODEC_I2C, ENABLE);
+
+}
+
+/**
+ * @brief Restore the Audio Codec control interface to its default state.
+ * This function doesn't de-initialize the I2C because the I2C peripheral
+ * may be used by other modules.
+ * @param None
+ * @retval None
+ */
+static void Codec_CtrlInterface_DeInit(void)
+{
+ /* Disable the I2C peripheral */ /* This step is not done here because
+ the I2C interface can be used by other modules */
+ /*I2C_DeInit(CODEC_I2C); */
+}
+
+/**
+ * @brief Initializes the Audio Codec audio interface (I2S)
+ * @note This function assumes that the I2S input clock (through PLL_R in
+ * Devices RevA/Z and through dedicated PLLI2S_R in Devices RevB/Y)
+ * is already configured and ready to be used.
+ * @param AudioFreq: Audio frequency to be configured for the I2S peripheral.
+ * @retval None
+ */
+static void Codec_AudioInterface_Init(uint32_t AudioFreq)
+{
+ I2S_InitTypeDef I2S_InitStructure;
+
+ /* Enable the CODEC_I2S peripheral clock */
+ RCC_APB1PeriphClockCmd(CODEC_I2S_CLK, ENABLE);
+
+ /* Deinitialize SPI3_I2S3 peripheral */
+ SPI_I2S_DeInit(CODEC_I2S);
+
+ /* CODEC_I2S peripheral configuration */
+ SPI_I2S_DeInit(CODEC_I2S);
+ I2S_InitStructure.I2S_AudioFreq = AudioFreq;
+ I2S_InitStructure.I2S_Standard = I2S_Standard_MSB;
+ I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
+ I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
+ I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
+#ifdef CODEC_MCLK_ENABLED
+ I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
+#elif defined(CODEC_MCLK_DISABLED)
+ I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
+#else
+ #error "No selection for the MCLK output has been defined !"
+#endif /* CODEC_MCLK_ENABLED */
+
+ /* Initialize the I2S peripheral with the structure above */
+ I2S_Init(CODEC_I2S, &I2S_InitStructure);
+
+ /* The I2S peripheral will be enabled only in the EVAL_AUDIO_Play() function
+ or by user functions if DMA mode not enabled */
+}
+
+/**
+ * @brief Restores the Audio Codec audio interface to its default state.
+ * @param None
+ * @retval None
+ */
+static void Codec_AudioInterface_DeInit(void)
+{
+ /* Disable the CODEC_I2S peripheral (in case it hasn't already been disabled) */
+ I2S_Cmd(CODEC_I2S, DISABLE);
+
+ /* Deinitialize the CODEC_I2S peripheral */
+ SPI_I2S_DeInit(CODEC_I2S);
+
+ /* Disable the CODEC_I2S peripheral clock */
+ RCC_APB1PeriphClockCmd(CODEC_I2S_CLK, DISABLE);
+}
+
+/**
+ * @brief Initializes IOs used by the Audio Codec (on the control and audio
+ * interfaces).
+ * @param None
+ * @retval None
+ */
+static void Codec_GPIO_Init(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ NVIC_InitTypeDef NVIC_InitStructure;
+ I2S_InitTypeDef I2S_InitStructure;
+
+ /* Enable I2S and I2C GPIO clocks */
+ RCC_AHBPeriphClockCmd(CODEC_I2C_GPIO_CLOCK | CODEC_I2S_GPIO_CLOCK, ENABLE);
+
+ /* Connect pins to I2C peripheral */
+ GPIO_PinAFConfig(CODEC_I2C_SCL_GPIO, CODEC_I2S_SCL_PINSRC, CODEC_I2C_GPIO_AF);
+ GPIO_PinAFConfig(CODEC_I2C_SDA_GPIO, CODEC_I2S_SDA_PINSRC, CODEC_I2C_GPIO_AF);
+
+ /* CODEC_I2C SCL and SDA pins configuration ----------------------------------*/
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2C_SDA_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(CODEC_I2C_SDA_GPIO, &GPIO_InitStructure);
+
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2C_SCL_PIN ;
+ GPIO_Init(CODEC_I2C_SCL_GPIO, &GPIO_InitStructure);
+
+ /* Connect pins to I2S peripheral */
+ GPIO_PinAFConfig(CODEC_I2S_MCK_WS_GPIO, CODEC_I2S_WS_PINSRC, CODEC_I2S_GPIO_AF);
+ GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SCK_PINSRC, CODEC_I2S_GPIO_AF);
+ GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_DIN_PINSRC, CODEC_I2S_GPIO_AF);
+ GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_DOUT_PINSRC, CODEC_I2S_GPIO_AF);
+
+ /* CODEC_I2S pins configuration: WS, SCK, DIN and DOUT pins -------------------------*/
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_SCK_PIN | CODEC_I2S_DIN_PIN | CODEC_I2S_DOUT_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(CODEC_I2S_GPIO, &GPIO_InitStructure);
+
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_WS_PIN;
+ GPIO_Init(CODEC_I2S_MCK_WS_GPIO, &GPIO_InitStructure);
+
+ #ifdef CODEC_MCLK_ENABLED
+ /* CODEC_I2S pins configuration: MCK pin */
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_MCK_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(CODEC_I2S_MCK_WS_GPIO, &GPIO_InitStructure);
+ /* Connect pins to I2S peripheral */
+ GPIO_PinAFConfig(CODEC_I2S_MCK_WS_GPIO, CODEC_I2S_MCK_PINSRC, CODEC_I2S_MCK_GPIO_AF);
+ #endif /* CODEC_MCLK_ENABLED */
+
+ /* SPI3/I2S3 IRQ Channel configuration */
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+
+ NVIC_InitStructure.NVIC_IRQChannel = SPI3_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
+
+ /* Deinitialize SPI3_I2S3 peripheral */
+ SPI_I2S_DeInit(CODEC_I2S);
+ /* I2S3 configuration ---------------------------------------//
+ SPI3_I2S3 - configured as follow:
+ - Work as Master & (transmiter) Rx
+ - 16bit data
+ - (Disable) Output MCLK
+ - Audio sample rate: 11kHz(have to use 8k/24k for CS42L52 ?)
+ - Default clock polarity: low level */
+ I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
+ I2S_InitStructure.I2S_Standard = I2S_Standard_MSB;
+ I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
+ I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
+ I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_32k;
+ I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
+ I2S_Init(CODEC_I2S, &I2S_InitStructure);
+ /* Disable the I2S3 TXE Interrupt */
+ SPI_I2S_ITConfig(CODEC_I2S, SPI_I2S_IT_TXE, DISABLE);
+ /* Enable the SPI3/I2S3 peripheral */
+ I2S_Cmd(CODEC_I2S, ENABLE);
+
+}
+
+/**
+ * @brief Initializes IOs used by the Audio Codec (on the control and audio
+ * interfaces).
+ * @param None
+ * @retval None
+ */
+static void Codec_GPIO_Recorder_Init(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ NVIC_InitTypeDef NVIC_InitStructure;
+ I2S_InitTypeDef I2S_InitStructure;
+
+ /* Enable I2S and I2C GPIO clocks */
+ RCC_AHBPeriphClockCmd(CODEC_I2C_GPIO_CLOCK | CODEC_I2S_GPIO_CLOCK, ENABLE);
+
+ /* Connect pins to I2C peripheral */
+ GPIO_PinAFConfig(CODEC_I2C_SCL_GPIO, CODEC_I2S_SCL_PINSRC, CODEC_I2C_GPIO_AF);
+ GPIO_PinAFConfig(CODEC_I2C_SDA_GPIO, CODEC_I2S_SDA_PINSRC, CODEC_I2C_GPIO_AF);
+
+ /* CODEC_I2C SCL and SDA pins configuration ----------------------------------*/
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2C_SDA_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+ GPIO_Init(CODEC_I2C_SDA_GPIO, &GPIO_InitStructure);
+
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2C_SCL_PIN ;
+ GPIO_Init(CODEC_I2C_SCL_GPIO, &GPIO_InitStructure);
+
+ /* Connect pins to I2S peripheral */
+ GPIO_PinAFConfig(CODEC_I2S_MCK_WS_GPIO, CODEC_I2S_WS_PINSRC, CODEC_I2S_GPIO_AF);
+ GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SCK_PINSRC, CODEC_I2S_GPIO_AF);
+ GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_DIN_PINSRC, CODEC_I2S_GPIO_AF);
+ GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_DOUT_PINSRC, CODEC_I2S_GPIO_AF);
+
+ /* CODEC_I2S pins configuration: WS, SCK, DIN and DOUT pins -------------------------*/
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_SCK_PIN | CODEC_I2S_DIN_PIN | CODEC_I2S_DOUT_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(CODEC_I2S_GPIO, &GPIO_InitStructure);
+
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_WS_PIN;
+ GPIO_Init(CODEC_I2S_MCK_WS_GPIO, &GPIO_InitStructure);
+
+ #ifdef CODEC_MCLK_ENABLED
+ /* CODEC_I2S pins configuration: MCK pin */
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_MCK_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(CODEC_I2S_MCK_WS_GPIO, &GPIO_InitStructure);
+ /* Connect pins to I2S peripheral */
+ GPIO_PinAFConfig(CODEC_I2S_MCK_WS_GPIO, CODEC_I2S_MCK_PINSRC, CODEC_I2S_MCK_GPIO_AF);
+ #endif /* CODEC_MCLK_ENABLED */
+
+
+ /* SPI3/I2S3 IRQ Channel configuration */
+ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
+
+ NVIC_InitStructure.NVIC_IRQChannel = SPI3_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
+
+ /* Deinitialize SPI3_I2S3 peripheral */
+ SPI_I2S_DeInit(CODEC_I2S);
+ /* I2S3 configuration ---------------------------------------//
+ SPI3_I2S3 - configured as follow:
+ - Work as Master & (transmiter) Rx
+ - 16bit data
+ - (Disable) Output MCLK
+ - Audio sample rate: 11kHz(have to use 8k/24k for CS42L52)
+ - Default clock polarity: low level */
+ I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
+ I2S_InitStructure.I2S_Standard = I2S_Standard_MSB;
+ I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
+ I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
+ I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_8k;
+ I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
+ I2S_Init(CODEC_I2S, &I2S_InitStructure);
+ /* configure Full Duplex */
+ I2S_FullDuplexConfig(I2S3ext, &I2S_InitStructure);
+ /* Disable the I2S3 TXE Interrupt */
+ SPI_I2S_ITConfig(CODEC_I2S, SPI_I2S_IT_TXE, DISABLE);
+ /* Enable the SPI3/I2S3 peripheral */
+ I2S_Cmd(CODEC_I2S, ENABLE);
+ I2S_Cmd(I2S3ext, ENABLE);
+}
+
+/**
+ * @brief Restores the IOs used by the Audio Codec interface to their default state.
+ * @param None
+ * @retval None
+ */
+static void Codec_GPIO_DeInit(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ /* Deinitialize all the GPIOs used by the driver (EXCEPT the I2C IOs since
+ they are used by the IOExpander as well) */
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_SCK_PIN | CODEC_I2S_DIN_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
+ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+ GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
+ GPIO_Init(CODEC_I2S_GPIO, &GPIO_InitStructure);
+
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_WS_PIN;
+ GPIO_Init(CODEC_I2S_MCK_WS_GPIO, &GPIO_InitStructure);
+
+#ifdef CODEC_MCLK_ENABLED
+ /* CODEC_I2S pins deinitialization: MCK pin */
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_MCK_PIN;
+ GPIO_Init(CODEC_I2S_MCK_WS_GPIO, &GPIO_InitStructure);
+ /* Disconnect pins from I2S peripheral */
+ GPIO_PinAFConfig(CODEC_I2S_MCK_WS_GPIO, CODEC_I2S_MCK_PINSRC, 0x00);
+#endif /* CODEC_MCLK_ENABLED */
+
+ GPIO_InitStructure.GPIO_Pin = CODEC_I2S_DOUT_PIN;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ GPIO_Init(CODEC_I2S_GPIO, &GPIO_InitStructure);
+
+ /* Disconnect pins from I2S peripheral */
+ GPIO_PinAFConfig(CODEC_I2S_MCK_WS_GPIO, CODEC_I2S_WS_PINSRC, 0x00);
+ GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SCK_PINSRC, 0x00);
+ GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_DIN_PINSRC, 0x00);
+ GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_DOUT_PINSRC, 0x00);
+}
+
+/**
+ * @brief Inserts a delay time (not accurate timing).
+ * @param nCount: specifies the delay time length.
+ * @retval None
+ */
+void Delay( __IO uint32_t nCount)
+{
+ for (; nCount != 0; nCount--);
+}
+
+#ifdef USE_DEFAULT_TIMEOUT_CALLBACK
+/**
+ * @brief Basic management of the timeout situation.
+ * @param None
+ * @retval None
+ */
+uint32_t Codec_TIMEOUT_UserCallback(void)
+{
+ /* The following code allows I2C error recovery and return to normal communication
+ if the error source doesn’t still exist (ie. hardware issue..) */
+ I2C_InitTypeDef I2C_InitStructure;
+
+
+ /* LCD_ErrLog("> I2C Timeout error occurred\n"); */
+ I2C_GenerateSTOP(CODEC_I2C, ENABLE);
+ /* Generated a Software reset */
+ I2C_SoftwareResetCmd(CODEC_I2C);
+
+ /* CODEC_I2C configuration */
+ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
+ I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
+ I2C_InitStructure.I2C_DigitalFilter = 0x00;
+ I2C_InitStructure.I2C_OwnAddress1 = 0x00;
+ I2C_InitStructure.I2C_Ack = I2C_Ack_Disable;
+ I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
+ I2C_InitStructure.I2C_Timing = CODEC_I2C_TIMING;
+
+ /* Enable the I2C peripheral */
+ I2C_Init(CODEC_I2C, &I2C_InitStructure);
+ I2C_Cmd(CODEC_I2C, ENABLE);
+
+ /* At this stage the I2C error should be recovered and device can communicate
+ again (except if the error source still exist).
+ User can implement mechanism (ex. test on max trial number) to manage situation
+ when the I2C can't recover from current error. */
+
+ /* LCD_UsrLog("> I2C error recovered.\n"); */
+
+ return 0;
+}
+#endif /* USE_DEFAULT_TIMEOUT_CALLBACK */
+
+/*============================================================================
+ Audio MAL Interface Control Functions
+ ============================================================================*/
+
+/**
+ * @brief Initializes and prepares the Media to perform audio data transfer
+ * from Media to the I2S peripheral.
+ * @param None
+ * @retval None
+ */
+static void Audio_MAL_Init(void)
+{
+#if defined(AUDIO_MAL_DMA_IT_TC_EN) || defined(AUDIO_MAL_DMA_IT_HT_EN) || defined(AUDIO_MAL_DMA_IT_TE_EN)
+ NVIC_InitTypeDef NVIC_InitStructure;
+#endif
+
+ /* Enable the DMA clock */
+ RCC_AHBPeriphClockCmd(AUDIO_MAL_DMA_CLOCK, ENABLE);
+
+ /* Configure the DMA Channel */
+ DMA_Cmd(AUDIO_MAL_DMA_CHANNEL, DISABLE);
+ DMA_DeInit(AUDIO_MAL_DMA_CHANNEL);
+ /* Set the parameters to be configured */
+
+ DMA_InitStructure.DMA_PeripheralBaseAddr = CODEC_I2S_ADDRESS;
+ DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)0; /* This field will be configured in play function */
+ DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
+ DMA_InitStructure.DMA_BufferSize = (uint32_t)0xFFFE; /* This field will be configured in play function */
+ DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+ DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+ DMA_InitStructure.DMA_PeripheralDataSize = AUDIO_MAL_DMA_PERIPH_DATA_SIZE;
+ DMA_InitStructure.DMA_MemoryDataSize = AUDIO_MAL_DMA_MEM_DATA_SIZE;
+#ifdef AUDIO_MAL_MODE_NORMAL
+ DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+#elif defined(AUDIO_MAL_MODE_CIRCULAR)
+ DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
+#else
+ #error "AUDIO_MAL_MODE_NORMAL or AUDIO_MAL_MODE_CIRCULAR should be selected !!"
+#endif /* AUDIO_MAL_MODE_NORMAL */
+ DMA_Init(AUDIO_MAL_DMA_CHANNEL, &DMA_InitStructure);
+
+ /* Enable the selected DMA interrupts (selected in "stm32_eval_audio_codec.h" defines) */
+#ifdef AUDIO_MAL_DMA_IT_TC_EN
+ DMA_ITConfig(AUDIO_MAL_DMA_CHANNEL, DMA_IT_TC, ENABLE);
+#endif /* AUDIO_MAL_DMA_IT_TC_EN */
+#ifdef AUDIO_MAL_DMA_IT_HT_EN
+ DMA_ITConfig(AUDIO_MAL_DMA_CHANNEL, DMA_IT_HT, ENABLE);
+#endif /* AUDIO_MAL_DMA_IT_HT_EN */
+#ifdef AUDIO_MAL_DMA_IT_TE_EN
+ DMA_ITConfig(AUDIO_MAL_DMA_CHANNEL, DMA_IT_TE | DMA_IT_FE | DMA_IT_DME, ENABLE);
+#endif /* AUDIO_MAL_DMA_IT_TE_EN */
+
+ /* Enable the I2S DMA request */
+ SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Tx, ENABLE);
+
+#if defined(AUDIO_MAL_DMA_IT_TC_EN) || defined(AUDIO_MAL_DMA_IT_HT_EN) || defined(AUDIO_MAL_DMA_IT_TE_EN)
+ /* I2S DMA IRQ Channel configuration */
+ NVIC_InitStructure.NVIC_IRQChannel = AUDIO_MAL_DMA_IRQ;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = EVAL_AUDIO_IRQ_PREPRIO;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = EVAL_AUDIO_IRQ_SUBRIO;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+#endif
+}
+
+/**
+ * @brief Restore default state of the used Media.
+ * @param None
+ * @retval None
+ */
+static void Audio_MAL_DeInit(void)
+{
+#if defined(AUDIO_MAL_DMA_IT_TC_EN) || defined(AUDIO_MAL_DMA_IT_HT_EN) || defined(AUDIO_MAL_DMA_IT_TE_EN)
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* Deinitialize the NVIC interrupt for the I2S DMA Channel */
+ NVIC_InitStructure.NVIC_IRQChannel = AUDIO_MAL_DMA_IRQ;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = EVAL_AUDIO_IRQ_PREPRIO;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = EVAL_AUDIO_IRQ_SUBRIO;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
+ NVIC_Init(&NVIC_InitStructure);
+#endif
+
+ /* Disable the DMA before the deinit */
+ DMA_Cmd(AUDIO_MAL_DMA_CHANNEL, DISABLE);
+
+ /* Dinitialize the DMA Channel */
+ DMA_DeInit(AUDIO_MAL_DMA_CHANNEL);
+
+ /* The DMA clock is not disabled */
+}
+
+/**
+ * @brief Starts playing audio stream from the audio Media.
+ * @param None
+ * @retval None
+ */
+void Audio_MAL_Play(uint32_t Addr, uint32_t Size)
+{
+ /* Configure the buffer address and size */
+ DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Addr;
+ DMA_InitStructure.DMA_BufferSize = (uint32_t)Size/2;
+
+ /* Configure the DMA Channel with the new parameters */
+ DMA_Init(AUDIO_MAL_DMA_CHANNEL, &DMA_InitStructure);
+
+ /* Enable the I2S DMA Channel */
+ DMA_Cmd(AUDIO_MAL_DMA_CHANNEL, ENABLE);
+}
+
+/**
+ * @brief Pauses or Resumes the audio stream playing from the Media.
+ * @param Cmd: AUDIO_PAUSE (or 0) to pause, AUDIO_RESUME (or any value different
+ * from 0) to resume.
+ * @param Addr: Address from/at which the audio stream should resume/pause.
+ * @retval None
+ */
+static void Audio_MAL_PauseResume(uint32_t Cmd, uint32_t Addr)
+{
+ /* Pause the audio file playing */
+ if (Cmd == AUDIO_PAUSE)
+ {
+ /* Disable the I2S DMA request */
+ SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Tx, DISABLE);
+
+ /* Pause the I2S DMA Channel
+ Note. For the STM32F30x devices, the DMA implements a pause feature,
+ by disabling the channel, all configuration is preserved and data
+ transfer is paused till the next enable of the channel.*/
+ DMA_Cmd(AUDIO_MAL_DMA_CHANNEL, DISABLE);
+ }
+ else /* AUDIO_RESUME */
+ {
+ /* Enable the I2S DMA request */
+ SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Tx, ENABLE);
+
+ /* Resume the I2S DMA Channel
+ Note. For the STM32F30x devices, the DMA implements a pause feature,
+ by disabling the channel, all configuration is preserved and data
+ transfer is paused till the next enable of the channel.*/
+ DMA_Cmd(AUDIO_MAL_DMA_CHANNEL, ENABLE);
+
+ /* If the I2S peripheral is still not enabled, enable it */
+ if ((CODEC_I2S->I2SCFGR & I2S_ENABLE_MASK) == 0)
+ {
+ I2S_Cmd(CODEC_I2S, ENABLE);
+ }
+ }
+}
+
+/**
+ * @brief Stops audio stream playing on the used Media.
+ * @param None
+ * @retval None
+ */
+static void Audio_MAL_Stop(void)
+{
+ /* Stop the Transfer on the I2S side: Stop and disable the DMA channel */
+ DMA_Cmd(AUDIO_MAL_DMA_CHANNEL, DISABLE);
+
+ /* Clear all the DMA flags for the next transfer */
+ DMA_ClearFlag(AUDIO_MAL_DMA_FLAG_TC|AUDIO_MAL_DMA_FLAG_HT|AUDIO_MAL_DMA_FLAG_TE);
+
+ /* The I2S DMA requests are not disabled here. */
+
+ /* In all modes, disable the I2S peripheral */
+ I2S_Cmd(CODEC_I2S, DISABLE);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/