aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Audio_Speaker/src/i2s_codec.c
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Audio_Speaker/src/i2s_codec.c')
-rw-r--r--thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Audio_Speaker/src/i2s_codec.c1573
1 files changed, 1573 insertions, 0 deletions
diff --git a/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Audio_Speaker/src/i2s_codec.c b/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Audio_Speaker/src/i2s_codec.c
new file mode 100644
index 0000000..6dd4168
--- /dev/null
+++ b/thirdparty/STM32_USB-FS-Device_Lib_V4.0.0/Projects/Audio_Speaker/src/i2s_codec.c
@@ -0,0 +1,1573 @@
+/**
+ ******************************************************************************
+ * @file i2s_codec.c
+ * @author MCD Application Team
+ * @version V4.0.0
+ * @date 21-January-2013
+ * @brief This file includes the I2S Codec driver for AK4343 Audio Codec.
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT 2013 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.
+ *
+ ******************************************************************************
+ */
+
+#include "platform_config.h"
+#ifdef USE_STM3210E_EVAL
+/* Includes ------------------------------------------------------------------*/
+
+#include "i2s_codec.h"
+
+/* Private typedef -----------------------------------------------------------*/
+typedef enum
+{
+ LittleEndian,
+ BigEndian
+}Endianness;
+
+/* Private define ------------------------------------------------------------*/
+
+/* Audio file header size */
+#define HEADER_SIZE 100
+
+/* EvalBoard pins related to the Codec */
+#define Codec_PDN_GPIO GPIOG
+#define Codec_PDN_Pin GPIO_Pin_11
+
+/* Uncomment this line to enable verifying data sent to codec after each write operation */
+//#define VERIFY_WRITTENDATA
+
+/* The 7 bits Codec address mask */
+#define CODEC_ADDRESS 0x27 /* b00100111 */
+
+/* Audio Parsing Constants */
+#define ChunkID 0x52494646 /* correspond to the letters 'RIFF' */
+#define FileFormat 0x57415645 /* correspond to the letters 'WAVE' */
+#define FormatID 0x666D7420 /* correspond to the letters 'fmt ' */
+#define DataID 0x64617461 /* correspond to the letters 'data' */
+#define FactID 0x66616374 /* correspond to the letters 'fact' */
+
+#define WAVE_FORMAT_PCM 0x01
+#define FormatChunkSize 0x10
+#define Channel_MONO 0x01
+#define Channel_STEREO 0x02
+
+#define SampleRate_8000 8000
+#define SampleRate_16000 16000
+#define SampleRate_22050 22050
+#define SampleRate_44100 44100
+#define SampleRate_48000 48000
+#define Bits_Per_Sample_8 8
+#define Bits_Per_Sample_16 16
+
+#define DUMMY_DATA 0x1111
+/* Private macro -------------------------------------------------------------*/
+/* Private variables ---------------------------------------------------------*/
+/* Audio Frequency value */
+uint16_t i2saudiofreq = I2S_AudioFreq_8k;
+
+/* Header Table containing the audio file information */
+uint8_t HeaderTabIndex = 0;
+uint8_t AudioFileHeader[HEADER_SIZE];
+
+/* Audio Codec variables */
+__IO uint32_t AudioFileAddress = 0x0;
+uint32_t AudioDataLength = 0;//7000000;
+uint32_t DataStartAddr = 0x0;
+__IO uint32_t AudioDataIndex = 0;
+static __IO uint32_t AudioReplay = 0xFFFF;
+static uint32_t AudioReplayCount = 0xFFFF;
+static __IO uint32_t SendDummyData = 0;
+static __IO uint32_t AudioPlayStatus = AudioPlayStatus_STOPPED;
+static uint32_t CurrentOutputDevice = OutputDevice_HEADPHONE;
+static uint8_t CurrentVolume = DEFAULT_VOL;
+static uint32_t errorcode = 0xFF;
+static __IO uint32_t monovar = 0, tmpvar = 0;
+
+/* Wave details names table */
+WAVE_FormatTypeDef WAVE_Format;
+__IO ErrorCode WaveFileStatus = Unvalid_RIFF_ID;
+
+/* Private function prototypes -----------------------------------------------*/
+/* Private functions ---------------------------------------------------------*/
+static void NVIC_Config(void);
+static void I2C_Config(void);
+static uint32_t CODEC_WriteRegister(uint32_t RegisterAddr, uint32_t RegisterValue);
+static uint32_t CODEC_ReadRegister(uint32_t RegisterAddr);
+static uint32_t ReadUnit(uint8_t NbrOfBytes, Endianness BytesFormat);
+uint32_t AudioFile_Init(void);
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_Init
+* Description : Initializes the I2S audio codec according parameters configured
+* by I2S_CODEC_Config function.
+* Input : - OutputDevice: Could be OutoutDevice_SPEAKER or
+* OutoutDevice_HEADPHONE.
+* - Address: Specifies the location of the audio file in the memory.
+* Output : None
+* Return : - 0: if all initializations are OK.
+* - 1: if memory initialization failed (LD2 is turned on).
+* - 2: if audio file initialization failed (LD2 is turned on).
+* - 3: if Codec initialization failed (LD1 is turned on).
+*******************************************************************************/
+uint32_t I2S_CODEC_Init(uint32_t OutputDevice, uint32_t Address)
+{
+ uint32_t count = 0;
+
+ /* Set the audio file address */
+ AudioFileAddress = (uint32_t) Address;
+
+ /* Configure I2S interrupt Channel */
+ NVIC_Config();
+
+ /* Configure the I2S2, I2C1 and GPIOF pins */
+ I2S_GPIO_Config();
+
+ /* Read the Audio file to extract the audio data length and frequency */
+ errorcode = AudioFile_Init();
+
+ if (errorcode < 3)
+ {
+ /* Turn on LD2 connected to PF.07 */
+ GPIO_SetBits(GPIOF, GPIO_Pin_7);
+
+ return errorcode;
+ }
+
+ /* Configure the SPI2 peripheral in I2S mode */
+ I2S_Config(I2S_STANDARD, I2S_MCLKOUTPUT, i2saudiofreq);
+
+ /* Set the current output device */
+ CurrentOutputDevice = OutputDevice;
+
+ /* Codec Configuration via I2C interface */
+ count = CODEC_Config(OutputDevice, I2S_STANDARD, I2S_MCLKOUTPUT, DEFAULT_VOL);
+
+ if (count != 0)
+ {
+ /* Turn on LD1 connected to PF.06 */
+ GPIO_SetBits(GPIOF, GPIO_Pin_6);
+
+ return 3;
+ }
+
+ /* Turn on LD4 connected to PF.09 */
+ GPIO_SetBits(GPIOF, GPIO_Pin_9);
+
+ return 0; /* Configuration is OK */
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_ReplayConfig
+* Description : Set AudioReplay variable value .
+* Input : Repetions: Number of repetitions
+* Output : None
+* Return : None
+*******************************************************************************/
+void I2S_CODEC_ReplayConfig(uint32_t Repetions)
+{
+ /* Audio Replay number set by user */
+ AudioReplay = Repetions;
+
+ /* Audio Replays number remaining (if AudioReplay != 0) */
+ AudioReplayCount = Repetions;
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_Play
+* Description : Plays the audio file.
+* Input : - AudioStartPosition: Address from which the wave data begin
+* Output : None
+* Return : AudioDataIndex value.
+*******************************************************************************/
+uint32_t I2S_CODEC_Play(uint32_t AudioStartPosition)
+{
+ /* Send the read command to the media */
+ Media_StartReadSequence(AudioFileAddress + AudioStartPosition + 1);
+
+ /* Set Playing status to inform other modules about the codec status */
+ SetVar_AudioPlayStatus(AudioPlayStatus_PLAYING);
+
+ /* Enable the I2S2 TXE Interrupt => Generate the clocks*/
+ SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, ENABLE);
+
+ return AudioDataIndex;
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_Pause
+* Description : Pause playing the audio file.
+* Input : None
+* Output : None
+* Return : Current Position.
+*******************************************************************************/
+uint32_t I2S_CODEC_Pause()
+{
+ /* Disable the I2S2 TXE Interrupt => stop the clocks*/
+ SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
+
+ /* Set Paused status to inform other modules about the codec status */
+ SetVar_AudioPlayStatus(AudioPlayStatus_PAUSED);
+
+ /* Reset local variables */
+ monovar = 0;
+ tmpvar = 0;
+
+ if (WAVE_Format.NumChannels == Channel_MONO)
+ {
+ /* Force the parity of the address */
+ AudioDataIndex &= 0xFFFFFFFE;
+ }
+ /* Return the current data pointer position */
+ return AudioDataIndex;
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_Stop
+* Description : Stop playing the audio file, reset the pointer and power off
+* : the Codec.
+* Input : None
+* Output : None
+* Return : 0 if operation complete.
+*******************************************************************************/
+uint32_t I2S_CODEC_Stop()
+{
+ /* Disable the I2S2 TXE Interrupt => stop the clocks */
+ SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
+
+ /* Reinitialize the audio data pointer */
+ AudioDataIndex = 0;
+
+ /* Power off the Codec to save power and protect the Codec itself */
+ I2S_CODEC_PowerDown(CodecPowerDown_SW);
+
+ /* Set Paused status to inform other modules about the codec status */
+ SetVar_AudioPlayStatus(AudioPlayStatus_STOPPED);
+
+ /* Reset local variables */
+ monovar = 0;
+ tmpvar = 0;
+
+ return 0;
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_ControlVolume
+* Description : Controls the audio volume.
+* Input : - direction: VolumeDirection_HIGH (0xF) to increase the volume,
+* : VolumeDirection_LOW (0xA) to decrease the volume or
+* : VolumeDirection_LEVEL (0x0) to set a defined level of volume.
+* : - Volume: the step of volume increasing/decreasing (when direction == 0)
+* : or the volume level to be set (when direction != 0).
+* Output : None
+* Return : 0-> correct communication, else wrong communication
+*******************************************************************************/
+uint32_t I2S_CODEC_ControlVolume(uint32_t direction, uint8_t Volume)
+{
+ uint32_t counter = 0;
+
+ if (direction == VolumeDirection_HIGH)
+ {
+ /* Check if the volume high limit is reached */
+ if (CurrentVolume < VOLStep)
+ {
+ CurrentVolume = 0;
+ }
+ else
+ {
+ /* Save the current volume level */
+ CurrentVolume = CODEC_ReadRegister(0x0A) - Volume;
+ }
+
+ /* Set the new volume */
+ counter += CODEC_WriteRegister(0x0A, CurrentVolume);
+ }
+ else if (direction == VolumeDirection_LOW)
+ {
+ /* Check if the volume low limit is reached */
+ if (CurrentVolume > (0xFF - VOLStep))
+ {
+ CurrentVolume = 0xFF;
+ }
+ else
+ {
+ /* Save the current volume level */
+ CurrentVolume = CODEC_ReadRegister(0x0A) + Volume;
+ }
+
+ /* Set the new volume */
+ counter += CODEC_WriteRegister(0x0A, CurrentVolume);
+ }
+ else if (direction == VolumeDirection_LEVEL)
+ {
+ CurrentVolume = Volume;
+
+ /* Set the new volume */
+ counter += CODEC_WriteRegister(0x0A, Volume);
+ }
+ else
+ {
+ return 0xFF; //Error verifying the Codec registers
+ }
+
+ return counter;
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_Mute
+* Description : Enable or disable the MUTE mode by software
+* Input : - Command: could be MUTEON to mute sound or MUTEOFF to restore volume
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void I2S_CODEC_Mute(uint32_t Command)
+{
+ uint32_t tmp = 0;
+
+ /* Read the current value of the config register number 0x0E */
+ tmp = CODEC_ReadRegister(0x0E);
+
+ /* Set the Mute mode */
+ if (Command == MUTE_ON)
+ {
+ tmp |= 0x20;
+ }
+ else /* MUTE_OFF Disable the Mute */
+ {
+ tmp &= 0xD1;
+ }
+
+ /* Write back the CODEC config register w/the new value */
+ CODEC_WriteRegister(0x0E, tmp);
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_ForwardPlay
+* Description : Forward function.
+* Input : - Step: number of steps forward
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void I2S_CODEC_ForwardPlay(uint32_t Step)
+{
+ /* Pause Playing the audio file */
+ I2S_CODEC_Pause();
+
+ /* Increment the Audio pointer */
+ IncrementVar_AudioDataIndex((AudioDataLength / 100) * Step);
+
+ /* Insure the index parity */
+ AudioDataIndex &= 0xFFFFFFFE;
+
+ /* Resume playing from the new position */
+ I2S_CODEC_Play((GetVar_AudioDataIndex()));
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_RewindPlay
+* Description : Rewind function.
+* Input : - Step: number of steps back
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void I2S_CODEC_RewindPlay(uint32_t Step)
+{
+ /* Pause Playing the audio file */
+ I2S_CODEC_Pause();
+
+ /* Increment the Audio pointer */
+ DecrementVar_AudioDataIndex((AudioDataLength / 100) * Step);
+
+ /* Insure the index parity */
+ AudioDataIndex &= 0xFFFFFFFE;
+
+ /* Resume playing from the new position */
+ I2S_CODEC_Play((GetVar_AudioDataIndex()));
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_PowerDown
+* Description : Power down the Audio Codec.
+* Input : - CodecPowerDown_Mode: could be CodecPowerDown_SW for power down
+* : after communication, CodecPowerDown_HW simply shut down the codec
+* Output : None
+* Return : None
+*******************************************************************************/
+void I2S_CODEC_PowerDown(uint32_t CodecPowerDown_Mode)
+{
+ if (CodecPowerDown_Mode == CodecPowerDown_SW)
+ {
+ /* Power down the DAC and the speaker (PMDAC and PMSPK bits)*/
+ (void)CODEC_WriteRegister(0x00, 0x40);
+ /* Power down the VCOM*/
+ (void)CODEC_WriteRegister(0x00, 0x00);
+ }
+ else /* CodecPowerDown_HW */
+ {
+ /* Power Down the Codec */
+ GPIO_ResetBits(Codec_PDN_GPIO, Codec_PDN_Pin);
+ }
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_Reset
+* Description : Reset the Audio Codec.
+* Input : None.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void I2S_CODEC_Reset(void)
+{
+ /* Power Down the Codec */
+ GPIO_ResetBits(Codec_PDN_GPIO, Codec_PDN_Pin);
+
+ /* wait for a delay to allow registers erasing */
+ delay(0xFF);
+
+ /* Power On the Codec after the power off => all registers are reinitialized*/
+ GPIO_SetBits(Codec_PDN_GPIO, Codec_PDN_Pin);
+
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_SpeakerHeadphoneSwap
+* Description : Configure the Audio Codec output to Speaker or Headphone while
+* : the audio wave is Paused or stopped.
+* Input : - OutputDevice: could be OutputDevice_Speaker or OutputDevice_Headphone
+* or OutputDevice_Both .
+* - Address: Specifies the audio file location in the memory.
+* Output : None.
+* Return : - 0: Operation done without failures.
+* - 1: Memory failure occur.
+* - 2: Audio file initialization failure occur
+* - 3: I2C communication failure occur
+*******************************************************************************/
+uint32_t I2S_CODEC_SpeakerHeadphoneSwap(uint32_t OutputDevice, uint32_t Address)
+{
+ uint32_t tmp_pointer = 0, err = 0;
+
+ /* Reset all Codec Registers */
+ I2S_CODEC_Reset();
+
+ /* Save the current position */
+ tmp_pointer = GetVar_AudioDataIndex();
+
+ /* Reinitialize the CODEC with the new configured parameters */
+ err = I2S_CODEC_Init(OutputDevice, Address);
+
+ if (err != 0)
+ {
+ return err;
+ }
+
+ /* Restore the last pointer position */
+ AudioDataIndex = tmp_pointer;
+
+ /* Restore the last volume level */
+ I2S_CODEC_ControlVolume(VolumeDirection_LEVEL, CurrentVolume);
+
+ /* Play from current position */
+ I2S_CODEC_Play(tmp_pointer);
+
+ return 0;
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_UpdateStatus
+* Description : Check if STOP or PAUSE command are generated and performs the
+* : relative action (STOP or PAUSE playing)
+* Input : None.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void I2S_CODEC_UpdateStatus(void)
+{
+ /* STOP command is generated => Stop playing the audio file */
+ if ((GetVar_AudioPlayStatus() == AudioPlayStatus_STOPPED) && (SPI_I2S_GetFlagStatus(SPI2, I2S_FLAG_CHSIDE) == SET))
+ {
+ I2S_CODEC_Stop();
+ }
+
+ /* PAUSE Command is generated => PAUSE playing the audio File */
+ if ((GetVar_AudioPlayStatus() == AudioPlayStatus_PAUSED) && (SPI_I2S_GetFlagStatus(SPI2, I2S_FLAG_CHSIDE) == SET))
+ {
+ I2S_CODEC_Pause();
+ }
+}
+
+/*******************************************************************************
+* Function Name : GetVar_DataStartAddr
+* Description : returns DataStartAddr variable value (used by stm32f10x_it.c file).
+* Input : None
+* Output : None
+* Return : AudioDataIndex
+*******************************************************************************/
+uint32_t GetVar_DataStartAddr(void)
+{
+ return DataStartAddr;
+}
+
+
+/*******************************************************************************
+* Function Name : GetVar_CurrentVolume
+* Description : returns CurrentVolume variable value (used by extern files).
+* Input : None
+* Output : None
+* Return : CurrentVolume
+*******************************************************************************/
+uint8_t GetVar_CurrentVolume(void)
+{
+ return CurrentVolume;
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_WaveParsing
+* Description : Checks the format of the .WAV file and gets information about
+* the audio format. This is done by reading the value of a
+* number of parameters stored in the file header and comparing
+* these to the values expected authenticates the format of a
+* standard .WAV file (44 bytes will be read). If it is a valid
+* .WAV file format, it continues reading the header to determine
+* the audio format such as the sample rate and the sampled data
+* size. If the audio format is supported by this application,
+* it retrieves the audio format in WAVE_Format structure and
+* returns a zero value. Otherwise the function fails and the
+* return value is nonzero.In this case, the return value specifies
+* the cause of the function fails. The error codes that can be
+* returned by this function are declared in the header file.
+* Input : None
+* Output : None
+* Return : Zero value if the function succeed, otherwise it return
+* a nonzero value which specifies the error code.
+*******************************************************************************/
+ErrorCode I2S_CODEC_WaveParsing(uint8_t* HeaderTab)
+{
+ uint32_t Temp = 0x00;
+ uint32_t ExtraFormatBytes = 0;
+
+ /* Initialize the HeaderTabIndex variable */
+ HeaderTabIndex = 0;
+
+ /* Read chunkID, must be 'RIFF' ----------------------------------------------*/
+ Temp = ReadUnit(4, BigEndian);
+ if (Temp != ChunkID)
+ {
+ return(Unvalid_RIFF_ID);
+ }
+ /* Read the file length ----------------------------------------------------*/
+ WAVE_Format.RIFFchunksize = ReadUnit(4, LittleEndian);
+
+ /* Read the file format, must be 'WAVE' ------------------------------------*/
+ Temp = ReadUnit(4, BigEndian);
+ if (Temp != FileFormat)
+ {
+ return(Unvalid_WAVE_Format);
+ }
+ /* Read the format chunk, must be 'fmt ' -----------------------------------*/
+ Temp = ReadUnit(4, BigEndian);
+ if (Temp != FormatID)
+ {
+ return(Unvalid_FormatChunk_ID);
+ }
+ /* Read the length of the 'fmt' data, must be 0x10 -------------------------*/
+ Temp = ReadUnit(4, LittleEndian);
+ if (Temp != 0x10)
+ {
+ ExtraFormatBytes = 1;
+ }
+ /* Read the audio format, must be 0x01 (PCM) -------------------------------*/
+ WAVE_Format.FormatTag = ReadUnit(2, LittleEndian);
+ if (WAVE_Format.FormatTag != WAVE_FORMAT_PCM)
+ {
+ return(Unsupporetd_FormatTag);
+ }
+ /* Read the number of channels: 0x02->Stereo 0x01->Mono --------------------*/
+ WAVE_Format.NumChannels = ReadUnit(2, LittleEndian);
+
+ /* Read the Sample Rate ----------------------------------------------------*/
+ WAVE_Format.SampleRate = ReadUnit(4, LittleEndian);
+
+ /* Update the I2S_AudioFreq value according to the .WAV file Sample Rate */
+ switch (WAVE_Format.SampleRate)
+ {
+ case SampleRate_8000 :
+ i2saudiofreq = I2S_AudioFreq_8k;
+ break;
+ case SampleRate_16000:
+ i2saudiofreq = I2S_AudioFreq_16k;
+ break;
+ case SampleRate_22050:
+ i2saudiofreq = I2S_AudioFreq_22k;
+ break;
+ case SampleRate_44100:
+ i2saudiofreq = I2S_AudioFreq_44k;
+ break;
+ case SampleRate_48000:
+ i2saudiofreq = I2S_AudioFreq_48k;
+ break;
+ default:
+ return(Unsupporetd_Sample_Rate);
+ }
+ /* Read the Byte Rate ------------------------------------------------------*/
+ WAVE_Format.ByteRate = ReadUnit(4, LittleEndian);
+
+ /* Read the block alignment ------------------------------------------------*/
+ WAVE_Format.BlockAlign = ReadUnit(2, LittleEndian);
+
+ /* Read the number of bits per sample --------------------------------------*/
+ WAVE_Format.BitsPerSample = ReadUnit(2, LittleEndian);
+ if (WAVE_Format.BitsPerSample != Bits_Per_Sample_16)
+ {
+ return(Unsupporetd_Bits_Per_Sample);
+ }
+ /* If there are Extra format bytes, these bytes will be defined in "Fact Chunk" */
+ if (ExtraFormatBytes == 1)
+ {
+ /* Read th Extra format bytes, must be 0x00 ------------------------------*/
+ Temp = ReadUnit(2, LittleEndian);
+ if (Temp != 0x00)
+ {
+ return(Unsupporetd_ExtraFormatBytes);
+ }
+ /* Read the Fact chunk, must be 'fact' -----------------------------------*/
+ Temp = ReadUnit(4, BigEndian);
+ if (Temp != FactID)
+ {
+ return(Unvalid_FactChunk_ID);
+ }
+ /* Read Fact chunk data Size ---------------------------------------------*/
+ Temp = ReadUnit(4, LittleEndian);
+
+ /* Set the index to start reading just after the header end */
+ HeaderTabIndex += Temp;
+ }
+ /* Read the Data chunk, must be 'data' -------------------------------------*/
+ Temp = ReadUnit(4, BigEndian);
+ if (Temp != DataID)
+ {
+ return(Unvalid_DataChunk_ID);
+ }
+ /* Read the number of sample data ------------------------------------------*/
+ WAVE_Format.DataSize = ReadUnit(4, LittleEndian);
+
+ /* Set the data pointer at the beginning of the effective audio data */
+ DataStartAddr += HeaderTabIndex;
+
+ return(Valid_WAVE_File);
+}
+
+/*******************************************************************************
+* Function Name : GetVar_AudioDataIndex
+* Description : returns AudioDataIndex variable value (used by stm32f10x_it.c file).
+* Input : None
+* Output : None
+* Return : AudioDataIndex
+*******************************************************************************/
+uint32_t GetVar_AudioDataIndex(void)
+{
+ return AudioDataIndex;
+}
+
+/*******************************************************************************
+* Function Name : SetVar_AudioDataIndex
+* Description : Sets AudioDataIndex variable value (used by stm32f10x_it.c file).
+* Input : None
+* Output : None
+* Return : AudioDataIndex
+*******************************************************************************/
+void SetVar_AudioDataIndex(uint32_t value)
+{
+ AudioDataIndex = value;
+}
+
+/*******************************************************************************
+* Function Name : IncrementVar_AudioDataIndex
+* Description : Increment the AudioDataIndex variable.
+* Input : - IncrementNumber: number of incrementations.
+* Output : None
+* Return : None
+*******************************************************************************/
+void IncrementVar_AudioDataIndex(uint32_t IncrementNumber)
+{
+ AudioDataIndex += (uint32_t)IncrementNumber;
+
+ if (AudioDataIndex >= AudioDataLength)
+ {
+ ResetVar_AudioDataIndex();
+ Decrement_AudioReplay();
+ }
+}
+
+/*******************************************************************************
+* Function Name : DecrementVar_AudioDataIndex
+* Description : Set the AudioDataIndex variable to 1.
+* Input : None
+* Output : None
+* Return : None.
+*******************************************************************************/
+void DecrementVar_AudioDataIndex(uint32_t DecrementNumber)
+{
+ if (DecrementNumber >= AudioDataIndex)
+ {
+ ResetVar_AudioDataIndex();
+ }
+ else
+ {
+ AudioDataIndex -= (uint32_t)DecrementNumber;
+ }
+}
+
+/*******************************************************************************
+* Function Name : ResetVar_AudioDataIndex
+* Description : Reset the AudioDataIndex variable.
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void ResetVar_AudioDataIndex(void)
+{
+ AudioDataIndex = DataStartAddr;
+
+ /* Send the read command to the media */
+ Media_StartReadSequence(AudioFileAddress + DataStartAddr + 1);
+}
+
+/*******************************************************************************
+* Function Name : GetVar_SendDummyData
+* Description : returns SendDummyData variable value (used by stm32f10x_it.c file).
+* Input : None
+* Output : None
+* Return : SendDummyData
+*******************************************************************************/
+uint32_t GetVar_SendDummyData(void)
+{
+ return SendDummyData;
+}
+
+/*******************************************************************************
+* Function Name : SetVar_SendDummyData
+* Description : Set the SendDummyData variable to 1.
+* Input : None
+* Output : None
+* Return : SendDummyData
+*******************************************************************************/
+uint32_t SetVar_SendDummyData(void)
+{
+ SendDummyData = (uint32_t)0x1;
+
+ return SendDummyData;
+}
+
+/*******************************************************************************
+* Function Name : ResetVar_SendDummyData
+* Description : Reset the SendDummyData variable to 0.
+* Input : None
+* Output : None
+* Return : SendDummyData
+*******************************************************************************/
+uint32_t ResetVar_SendDummyData(void)
+{
+ SendDummyData = (uint32_t)0;
+
+ return SendDummyData;
+}
+
+/*******************************************************************************
+* Function Name : GetVar_AudioPlayStatus
+* Description : returns AudioPlayStatus variable value (used by stm32f10x_it.c file).
+* Input : None
+* Output : None
+* Return : AudioPlayStatus value.
+*******************************************************************************/
+uint32_t GetVar_AudioPlayStatus(void)
+{
+ return AudioPlayStatus;
+}
+
+/*******************************************************************************
+* Function Name : SetVar_AudioPlayStatus
+* Description : Set the AudioDataIndex variable to Status.
+* Input : Status: could be AudioPlayStatus_STOPPED, AudioPlayStatus_PLAYING
+* : or AudioPlayStatus_PAUSED.
+* Output : None
+* Return : AudioPlayStatus value.
+*******************************************************************************/
+uint32_t SetVar_AudioPlayStatus(uint32_t Status)
+{
+ AudioPlayStatus = (uint32_t)Status;
+
+ return AudioPlayStatus;
+}
+
+/*******************************************************************************
+* Function Name : GetVar_AudioReplay
+* Description : returns AudioReplay variable value.
+* Input : None
+* Output : None
+* Return : AudioReplay value.
+*******************************************************************************/
+uint32_t GetVar_AudioReplay(void)
+{
+ return AudioReplay;
+}
+
+/*******************************************************************************
+* Function Name : SetVar_AudioReplay
+* Description : Decrement the AudioReplayCount variable if AudioReplay is different
+* : from zero (infinite replaying).
+* Input : None.
+* Output : None
+* Return : AudioPlayStatus value.
+*******************************************************************************/
+void Decrement_AudioReplay(void)
+{
+ if (AudioReplay != 0)
+ {
+ AudioReplayCount--;
+
+ if (AudioReplayCount == 0)
+ {
+ /* Command the Stop of the audio playing */
+ SetVar_AudioPlayStatus(AudioPlayStatus_STOPPED);
+
+ /* Reset the counter */
+ AudioReplayCount = AudioReplay;
+ }
+ }
+}
+
+/*******************************************************************************
+* Function Name : GetVar_CurrentOutputDevice
+* Description : Get the current output device selected .
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+uint32_t GetVar_CurrentOutputDevice(void)
+{
+ return CurrentOutputDevice;
+}
+
+/*******************************************************************************
+* Function Name : GetVar_AudioDataLength
+* Description : Get the current audio file data length .
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+uint32_t GetVar_AudioDataLength(void)
+{
+ return AudioDataLength;
+}
+
+/*******************************************************************************
+* Function Name : GetVar_i2saudiofreq
+* Description : Get the current audio frequency .
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+uint16_t GetVar_i2saudiofreq(void)
+{
+ return i2saudiofreq;
+}
+
+/*******************************************************************************
+* Function Name : AudioFile_Init
+* Description : Initializes the SPI_Flash and returns the Wavadatalength variable.
+* Input : None
+* Output : None
+* Return : - The length of the wave file read from the SPI_Flash
+* - 1 if an error occurred when initializing the memory.
+* - 2 if an error occurred on the audio file initialization.
+*******************************************************************************/
+uint32_t AudioFile_Init(void)
+{
+ uint32_t err = 0;
+
+ /* Initialize the media support */
+ err = Media_Init();
+
+ /* Check if Memory initialization is OK */
+ if (err != 0)
+ {
+ return 1;
+ }
+
+ /* Read a Byte buffer and store it in the Header table*/
+ Media_BufferRead(AudioFileHeader, AudioFileAddress, HEADER_SIZE);
+
+ /* Read and check the audio file Header */
+ WaveFileStatus = I2S_CODEC_WaveParsing(AudioFileHeader);
+
+ /* Check if the selected file is a correct wave file */
+ if (WaveFileStatus == Valid_WAVE_File)
+ {
+ /* Read and set the audio data length (/!\ data are counted as BYTES /!\) */
+ AudioDataLength = WAVE_Format.DataSize ;
+
+ /* Read and set the audio frequency */
+ i2saudiofreq = (uint16_t)WAVE_Format.SampleRate;
+
+ /* Return the audio file length */
+ return AudioDataLength;
+ }
+ else /* Wrong wave file */
+ {
+ return 2;
+ }
+}
+
+/*******************************************************************************
+* Function Name : NVIC_Config
+* Description : Configure the I2Ss NVIC channel.
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+static void NVIC_Config(void)
+{
+ NVIC_InitTypeDef NVIC_InitStructure;
+
+ /* SPI2 IRQ Channel configuration */
+ NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+}
+
+/*******************************************************************************
+* Function Name : GPIO_Config
+* Description : Initializes the GPIO pins used by the codec application.
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+void I2S_GPIO_Config(void)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ /* Enable GPIOB, GPIOC and AFIO clock */
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOG |
+ RCC_APB2Periph_GPIOF | RCC_APB2Periph_AFIO, ENABLE);
+
+ /* I2S2 SD, CK and WS pins configuration */
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_15;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ /* I2S2 MCK pin configuration */
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
+ GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+ /* LEDs pins configuration */
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_Init(GPIOF, &GPIO_InitStructure);
+
+ /* I2C1 SCL PB6 and SDA PB7 pins configuration */
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
+ GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ /* Enable the I2C1 APB1 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
+
+ /* Turn Off All LEDs */
+ GPIO_ResetBits(GPIOF, GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9);
+ GPIO_ResetBits(Codec_PDN_GPIO, Codec_PDN_Pin);
+
+ /* Configure the Codec PDN pin as output PushPull */
+ GPIO_InitStructure.GPIO_Pin = Codec_PDN_Pin;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+ GPIO_Init(Codec_PDN_GPIO, &GPIO_InitStructure);
+}
+
+/*******************************************************************************
+* Function Name : I2S_Config
+* Description : Configure the I2S Peripheral.
+* Input : - Standard: I2S_Standard_Phillips, I2S_Standard_MSB or I2S_Standard_LSB
+* - MCLKOutput: I2S_MCLKOutput_Enable or I2S_MCLKOutput_Disable
+* - AudioFreq: I2S_AudioFreq_8K, I2S_AudioFreq_16K, I2S_AudioFreq_22K,
+* I2S_AudioFreq_44K or I2S_AudioFreq_48K
+* Output : None
+* Return : None
+*******************************************************************************/
+void I2S_Config(uint16_t Standard, uint16_t MCLKOutput, uint16_t AudioFreq)
+{
+ I2S_InitTypeDef I2S_InitStructure;
+
+ /* Enable I2S2 APB1 clock */
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
+
+ /* Deinitialize SPI2 peripheral */
+ SPI_I2S_DeInit(SPI2);
+
+ /* I2S2 peripheral configuration */
+ I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
+ I2S_InitStructure.I2S_Standard = Standard;
+ I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_16b;
+ I2S_InitStructure.I2S_MCLKOutput = MCLKOutput;
+ I2S_InitStructure.I2S_AudioFreq = AudioFreq;
+ I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
+ I2S_Init(SPI2, &I2S_InitStructure);
+
+ /* Disable the I2S2 TXE Interrupt */
+ SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
+
+ /* Enable the SPI2/I2S2 peripheral */
+ I2S_Cmd(SPI2, ENABLE);
+}
+
+/*******************************************************************************
+* Function Name : I2C_Config
+* Description : Configure the I2C1 Peripheral.
+* Input : None
+* Output : None
+* Return : None
+*******************************************************************************/
+static void I2C_Config(void)
+{
+ I2C_InitTypeDef I2C_InitStructure;
+
+ /* I2C1 configuration */
+ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
+ I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
+ I2C_InitStructure.I2C_OwnAddress1 = 0x33;
+ I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
+ I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
+ I2C_InitStructure.I2C_ClockSpeed = 200000;
+ I2C_Init(I2C1, &I2C_InitStructure);
+}
+
+/*******************************************************************************
+* Function Name : CODEC_Config
+* Description : Configure the Codec in Headphone mode.
+* Input : - OutputDevice: OutputDeviceHEADPHONE or OutputDeviceSPEAKER
+* : - I2S_Standard: I2S communication standard could be I2S_Standard_Phillips
+* : I2S_Standard_MSB or I2S_Standard_LSB.
+* : - I2S_MCLKOutput: could be I2S_MCLKOutput_
+* : - Volume:
+* Output : None
+* Return : 0-> correct communication, else wrong communication
+*******************************************************************************/
+uint32_t CODEC_Config(uint16_t OutputDevice, uint16_t I2S_Standard, uint16_t I2S_MCLKOutput, uint8_t Volume)
+{
+ uint32_t Standard = 0, counter = 0, PLLMode = 0;
+
+ /* Command the sending of dummy data */
+ ResetVar_SendDummyData();
+
+ /* Reset the Codec Registers */
+ I2S_CODEC_Reset();
+
+ /* Determine the I2S standard used */
+ switch (I2S_Standard)
+ {
+ case I2S_Standard_Phillips:
+ Standard = 0x03;
+ break;
+ case I2S_Standard_MSB:
+ Standard = 0x02;
+ break;
+ default :
+ Standard = 0x01;
+ break;
+ }
+
+ /* HEADPHONE codec configuration */
+ if ((OutputDevice & OutputDevice_HEADPHONE) != 0)
+ {
+ /* PLL Slave SD/WS reference mode ----------------------*/
+ if (I2S_MCLKOutput == I2S_MCLKOutput_Disable)
+ {
+ /* set the PLLMode variable */
+ PLLMode = 0x1;
+
+ /* Phillips(0x03)/MSB(0x02)/LSB(0x01) mode with PLL */
+ counter += CODEC_WriteRegister(0x04, (Standard | 0x20));
+ /* MCKI input frequency = 256.Fs */
+ counter += CODEC_WriteRegister(0x05, 0x03);
+ /* VCOM Power up (PMVCM bit)*/
+ counter += CODEC_WriteRegister(0x00, 0x40);
+ /* Enable PLL*/
+ counter += CODEC_WriteRegister(0x01, 0x01);
+ }
+ /* Ext Slave mode with no PLL --------------------------*/
+ else
+ {
+ /* Reset the PLL mode variable */
+ PLLMode = 0;
+
+ /* Phillips(0x03)/MSB(0x02)/LSB(0x01) mode with no PLL */
+ counter += CODEC_WriteRegister(0x04, Standard);
+ /* MCKI input frequency = 256.Fs */
+ counter += CODEC_WriteRegister(0x05, 0x00);
+ /* VCOM Power up (PMVCM bit)*/
+ counter += CODEC_WriteRegister(0x00, 0x40);
+ }
+
+ /* Command the sending of dummy data */
+ SetVar_SendDummyData();
+
+ /* Enable the I2S2 TXE Interrupt => Generate the clocks*/
+ SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, ENABLE);
+
+ /* Extra Configuration (of the ALC) */
+ counter += CODEC_WriteRegister(0x06, 0x3C );
+ counter += CODEC_WriteRegister(0x08, 0xE1 );
+ counter += CODEC_WriteRegister(0x0B, 0x00 );
+ counter += CODEC_WriteRegister(0x07, 0x20 );
+ counter += CODEC_WriteRegister(0x09, 0xC1 );
+ counter += CODEC_WriteRegister(0x0C, 0xC1 );
+
+ /* MCKI is 256.Fs with no PLL */
+ counter += CODEC_WriteRegister(0x05, 0x00 );
+ /* Switch control from DAC to Headphone */
+ counter += CODEC_WriteRegister(0x0F, 0x09 );
+ /* Bass Boost and Deemphasis enable */
+ counter += CODEC_WriteRegister(0x0E, 0x18 );
+ /* Left Channel Digital Volume control */
+ counter += CODEC_WriteRegister(0x0A, Volume);
+ /* Right Channel Digital Volume control */
+ counter += CODEC_WriteRegister(0x0D, Volume);
+ /* Power up MIN and DAC (PMMIN and PMDAC bits)*/
+ counter += CODEC_WriteRegister(0x00, 0x74);
+ /* Enable Slave mode and Left/Right HP lines*/
+ counter += CODEC_WriteRegister(0x01, (0x30 | PLLMode));
+ /* Exit HP mute mode */
+ counter += CODEC_WriteRegister(0x01, (0x70 | PLLMode));
+ }
+
+ /* SPEAKER codec configuration */
+ if ((OutputDevice & OutputDevice_SPEAKER) != 0)
+ {
+ /* PLL Slave SD/WS reference mode ----------------------*/
+ if (I2S_MCLKOutput == I2S_MCLKOutput_Disable)
+ {
+ /* Phillips(0x03)/MSB(0x02)/LSB(0x01) mode with no PLL */
+ counter += CODEC_WriteRegister(0x04, (Standard | 0x20));
+ /* MCKI input frequency = 256.Fs */
+ counter += CODEC_WriteRegister(0x05, 0x03);
+ /* VCOM Power up (PMVCM bit)*/
+ counter += CODEC_WriteRegister(0x00, 0x40);
+ /* Enable PLL*/
+ counter += CODEC_WriteRegister(0x01, 0x01);
+ }
+ /* Ext Slave mode with no PLL --------------------------*/
+ else
+ {
+ /* Phillips(0x03)/MSB(0x02)/LSB(0x01) mode with no PLL */
+ counter += CODEC_WriteRegister(0x04, Standard);
+ /* MCKI input frequency = 256.Fs */
+ counter += CODEC_WriteRegister(0x05, 0x00);
+ /* VCOM Power up (PMVCM bit)*/
+ counter += CODEC_WriteRegister(0x00, 0x40);
+ }
+
+ /* Command the sending of dummy data */
+ SetVar_SendDummyData();
+
+ /* Enable the I2S2 TXE Interrupt => Generate the clocks*/
+ SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, ENABLE);
+
+ /* ReSelect the MCKI frequency (FS0-1 bits): 256.Fs */
+ counter += CODEC_WriteRegister(0x05, 0x02 );
+ /* Set up the path "DAC->Speaker-Amp" with no power save (DACS and SPPSN bits) */
+ counter += CODEC_WriteRegister(0x02, 0x20 );
+ /* Speaker Gain (SPKG0-1 bits): Gain=+10.65dB(ALC off)/+12.65(ALC on) */
+ counter += CODEC_WriteRegister(0x03, 0x10);
+
+ /* Extra Configuration (of the ALC) */
+ counter += CODEC_WriteRegister(0x06, 0x3C );
+ counter += CODEC_WriteRegister(0x08, 0xE1 );
+ counter += CODEC_WriteRegister(0x0B, 0x00 );
+ counter += CODEC_WriteRegister(0x07, 0x20 );
+ counter += CODEC_WriteRegister(0x09, 0x91 );
+ counter += CODEC_WriteRegister(0x0C, 0x91 );
+
+ /* Left Channel Digital Volume control */
+ counter += CODEC_WriteRegister(0x0A, Volume);
+ /* Right Channel Digital Volume control */
+ counter += CODEC_WriteRegister(0x0D, Volume);
+ /* Power up Speaker and DAC (PMSPK and PMDAC bits)*/
+ counter += CODEC_WriteRegister(0x00, 0x54);
+ /* Set up the path "DAC -> Speaker-Amp" with no power save */
+ counter += CODEC_WriteRegister(0x02, 0xA0 /*0xA1*/);
+ }
+
+ /* Disable the I2S2 TXE Interrupt */
+ SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
+
+ /* Disable the sending of Dummy data */
+ ResetVar_SendDummyData();
+
+ /* Return the counter value */
+ return counter;
+}
+
+/*******************************************************************************
+* Function Name : CODEC_WriteRegister
+* Description : Writes a value in a register of the audio Codec through I2C.
+* Input : - RegisterAddr: The target register address (between 00x and 0x24)
+* : - RegisterValue: The target register value to be written
+* : - Verify: 0-> Don't verify the written data, 1-> Verify the written data
+* Output : None
+* Return : - 0 -> Correct write operation
+* : - !0 -> Incorrect write operation
+*******************************************************************************/
+uint32_t CODEC_WriteRegister(uint32_t RegisterAddr, uint32_t RegisterValue)
+{
+ uint32_t read_verif = 0;
+
+ /* Reset all I2C2 registers */
+ I2C_SoftwareResetCmd(I2C1, ENABLE);
+ I2C_SoftwareResetCmd(I2C1, DISABLE);
+
+ /* Enable the I2C1 peripheral */
+ I2C_Cmd(I2C1, ENABLE);
+
+ /* Configure the I2C peripheral */
+ I2C_Config();
+
+ /* Begin the config sequence */
+ I2C_GenerateSTART(I2C1, ENABLE);
+
+ /* Test on EV5 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
+ {}
+ /* Transmit the slave address and enable writing operation */
+ I2C_Send7bitAddress(I2C1, CODEC_ADDRESS, I2C_Direction_Transmitter);
+
+ /* Test on EV6 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
+ {}
+ /* Transmit the first address for r/w operations */
+ I2C_SendData(I2C1, RegisterAddr);
+
+ /* Test on EV8 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
+ {}
+
+ /* Prepare the register value to be sent */
+ I2C_SendData(I2C1, RegisterValue);
+
+ /* Test on EV8 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
+ {}
+
+ /* End the configuration sequence */
+ I2C_GenerateSTOP(I2C1, ENABLE);
+
+ /* Verify (if needed) that the loaded data is correct */
+#ifdef VERIFY_WRITTENDATA
+ /* Read the just written register*/
+ read_verif = CODEC_ReadRegister(RegisterAddr);
+
+ /* Load the register and verify its value */
+ if (read_verif != RegisterValue)
+ {
+ /* Control data wrongly transferred */
+ read_verif = 1;
+ }
+ else
+ {
+ /* Control data correctly transferred */
+ read_verif = 0;
+ }
+#endif
+
+ /* Return the verifying value: 0 (Passed) or 1 (Failed) */
+ return read_verif;
+}
+
+/*******************************************************************************
+* Function Name : CODEC_ReadRegister
+* Description : Reads a register of the audio Codec through I2C.
+* Input : - RegisterAddr: The target register address (between 00x and 0x24)
+* Output : None
+* Return : The value of the read register
+*******************************************************************************/
+uint32_t CODEC_ReadRegister(uint32_t RegisterAddr)
+{
+ uint32_t tmp = 0;
+
+ /* Disable the I2C1 peripheral */
+ I2C_Cmd(I2C1, DISABLE);
+
+ /* Reset all I2C2 registers */
+ I2C_SoftwareResetCmd(I2C1, ENABLE);
+ I2C_SoftwareResetCmd(I2C1, DISABLE);
+
+ /* Configure the I2C peripheral */
+ I2C_Config();
+
+ /* Enable the I2C peripheral */
+ I2C_GenerateSTART(I2C1, ENABLE);
+
+ /* Test on EV5 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
+ {}
+
+ /* Disable Acknowledgement */
+ I2C_AcknowledgeConfig(I2C1, DISABLE);
+
+ /* Transmit the slave address and enable writing operation */
+ I2C_Send7bitAddress(I2C1, CODEC_ADDRESS, I2C_Direction_Transmitter);
+
+ /* Test on EV6 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
+ {}
+
+ /* Transmit the first address for r/w operations */
+ I2C_SendData(I2C1, RegisterAddr);
+
+ /* Test on EV8 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
+ {}
+
+ /* Regenerate a start condition */
+ I2C_GenerateSTART(I2C1, ENABLE);
+
+ /* Test on EV5 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
+ {}
+
+ /* Transmit the slave address and enable writing operation */
+ I2C_Send7bitAddress(I2C1, CODEC_ADDRESS, I2C_Direction_Receiver);
+
+ /* Test on EV6 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
+ {}
+
+ /* Test on EV7 and clear it */
+ while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))
+ {}
+
+ /* End the configuration sequence */
+ I2C_GenerateSTOP(I2C1, ENABLE);
+
+ /* Load the register value */
+ tmp = I2C_ReceiveData(I2C1);
+
+ /* Disable Acknowledgement */
+ I2C_AcknowledgeConfig(I2C1, ENABLE);
+
+ /* Return the read value */
+ return tmp;
+}
+
+/*******************************************************************************
+* Function Name : ReadUnit
+* Description : Reads a number of bytes from the SPI Flash and reorder them
+* in Big or little endian.
+* Input : - NbrOfBytes : number of bytes to read.
+* This parameter must be a number between 1 and 4.
+* - ReadAddr : external memory address to read from.
+* - Endians : specifies the bytes endianness.
+* This parameter can be one of the following values:
+* - LittleEndian
+* - BigEndian
+* Output : None
+* Return : Bytes read from the SPI Flash.
+*******************************************************************************/
+static uint32_t ReadUnit(uint8_t NbrOfBytes, Endianness BytesFormat)
+{
+ uint32_t index = 0;
+ uint32_t Temp = 0;
+
+ if (BytesFormat == LittleEndian)
+ {
+ for (index = 0; index < NbrOfBytes; index++)
+ {
+ Temp |= AudioFileHeader[HeaderTabIndex++] << (index * 8);
+ }
+ }
+ else
+ {
+ for (index = NbrOfBytes; index != 0; index--)
+ {
+ Temp |= AudioFileHeader[HeaderTabIndex++] << ((index - 1) * 8);
+ }
+ }
+
+ return Temp;
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_MediaReadHalfWord
+* Description : Read one half word from the media (SPI_Flash/NOR/NAND memories..)
+* Input : - Offset: the address offset for read operation
+* Output : None.
+* Return : Data read from the media memory.
+*******************************************************************************/
+uint16_t Media_ReadHalfWord(uint32_t Offset)
+{
+ /* Test if the left channel is to be sent */
+ if (monovar == 0)
+ {
+ /* Enable the FSMC that share a pin w/ I2C1 (LBAR) */
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
+
+ tmpvar = (*(__IO uint16_t *) (AudioFileAddress + Offset));
+
+ /* Disable the FSMC that share a pin w/ I2C1 (LBAR) */
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, DISABLE);
+
+ /* Increment the mono variable only if the file is in mono format */
+ if (WAVE_Format.NumChannels == Channel_MONO)
+ {
+ /* Increment the monovar variable */
+ monovar++;
+ }
+
+ /* Return the read value */
+ return tmpvar;
+ }
+ /* Right channel to be sent in mono format */
+ else
+ {
+ /* Reset the monovar variable */
+ monovar = 0;
+
+ /* Return the previous read data in mono format */
+ return tmpvar;
+ }
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_MediaReadByte
+* Description : Read one byte from the media (SPI_Flash/NOR/NAND memories..)
+* Input : - Offset: the address offset for read operation
+* Output : None.
+* Return : Data read from the media memory.
+*******************************************************************************/
+uint8_t Media_ReadByte(uint32_t Offset)
+{
+ uint8_t tmp = 0;
+
+ /* Enable the FSMC that share a pin w/ I2C1 (LBAR) */
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
+
+ /* Read data from the specified location */
+ tmp = (*(__IO uint8_t *) (AudioFileAddress + Offset));
+
+ /* Disable the FSMC that share a pin w/ I2C1 (LBAR) */
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, DISABLE);
+
+ return tmp;
+}
+
+/*******************************************************************************
+* Function Name : Media_Init
+* Description : Read one byte from the media (SPI_Flash/NOR/NAND memories..)
+* Input : - Offset: the address offset for read operation
+* Output : None.
+* Return : - 0 if initialization is OK
+* - 1 if initialization failed..
+*******************************************************************************/
+uint32_t Media_Init(void)
+{
+ return 0;
+}
+
+/*******************************************************************************
+* Function Name : Media_BufferRead
+* Description : Read a buffer from the memory media
+* Input : - pBuffer: Destination buffer address
+* : - ReadAddr: start reading position
+* : - NumByteToRead: size of the buffer to read
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void Media_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
+{
+ /* Enable the FSMC that share a pin w/ I2C1 (LBAR) */
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
+
+ /* Read the data */
+ while (NumByteToRead--)
+ {
+ *pBuffer++ = *(__IO uint8_t *)ReadAddr++;
+ }
+
+ /* Disable the FSMC that share a pin w/ I2C1 (LBAR) */
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, DISABLE);
+}
+
+/*******************************************************************************
+* Function Name : Media_StartReadSequence
+* Description : Initialize reading sequence on the media.
+* Input : - ReadAddr: start reading position
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void Media_StartReadSequence(uint32_t ReadAddr)
+{
+ /* This function could be used for memories needing a start read sequence
+ like SPI_Flash memory */
+}
+
+/*******************************************************************************
+* Function Name : I2S_CODEC_DataTransfer
+* Description : Sends the audio data using the SPI2 peripheral and checks the
+* : audio playing status (if a command (Pause/Stop) is pending
+* : the playing status is updated). If the TXE flag interrupt
+* : is used to synchronize data sending, this function should be
+* : called in the SPI2 ISR.
+* Input : None.
+* Output : None.
+* Return : None.
+*******************************************************************************/
+void I2S_CODEC_DataTransfer(void)
+{
+ /* Audio codec configuration section -------------------------------------*/
+ if (GetVar_SendDummyData() == 1)
+ {
+ /* Send a dummy data just to generate the I2S clock */
+ SPI_I2S_SendData(SPI2, DUMMY_DATA);
+ }
+ /* Audio codec communication section -------------------------------------*/
+ else
+ {
+ /* Send the data read from the memory */
+ SPI_I2S_SendData(SPI2, (Media_ReadHalfWord(AudioDataIndex)));
+
+ /* Increment the index */
+ IncrementVar_AudioDataIndex(WAVE_Format.NumChannels);
+
+ /* Check and update the stream playing status */
+ I2S_CODEC_UpdateStatus();
+ }
+}
+/*******************************************************************************
+* Function Name : delay
+* Description : Inserts a delay time.
+* Input : nCount: specifies the delay time length
+* Output : None
+* Return : The length of the wave file read from the SPI_Flash
+*******************************************************************************/
+void delay(__IO uint32_t nCount)
+{
+ for (; nCount != 0; nCount--);
+}
+#endif
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/