diff options
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.c | 1573 |
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>© 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****/ |