/** ****************************************************************************** * @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 * *

© COPYRIGHT 2013 STMicroelectronics

* * 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****/