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