?? i2s.cpp
字號:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name: I2S.CPP
Abstract: I2S Interface Routines for Samsung SC2410 CPU
Notes: This code assumes that the CPU acts as the master that is
connected to a CODEC chip configured in slave mode.
Some platforms require the audio CODEC chip to act as the master
while the CPU's IIS controller is put into slave mode. For these
environments, the IIS_MASTER_MODE flag (located in I2S_Init())
should be replaced with the IIS_SLAVE_MODE flag.
Environment: Samsung SC2410 CPU and Windows 3.0 (or later)
-*/
#include <windows.h>
#include "i2s.h"
//------------------------------ GLOBALS -------------------------------------------
extern volatile IISreg *v_pIISregs; // I2S control registers
extern volatile IOPreg *v_pIOPregs; // GPIO registers (needed to enable SPI)
extern volatile CLKPWRreg *g_pCLKPWRreg; // CLCKPWR (needed to enable SPI clocks)
//----------------------------------------------------------------------------------
//#define DEBUGMSG(a,b) RETAILMSG(0,b)
#ifdef DEBUG
#define ZONE_ERROR 1
#endif
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: I2S_Init()
Description: Initializes the IIS bus and controller.
Notes: This routine assumes that the control registers (see
the globals section above) have already been initialized.
Returns: Boolean indicating success.
-------------------------------------------------------------------*/
BOOL I2S_Init()
{
//----- 1. IMPORTANT: By default, the internal clock is disabled. To configure the controller ------
// we must first enable it.
// StartI2SClock();
g_pCLKPWRreg->rCLKCON |= IIS_INTERNAL_CLOCK_ENABLE; // Enable the CPU clock to the IIS controller
//----- 2. Configure the GPIO pins for I2S mode -----
//
// I2SSDO - GPE4
// I2SSDI - GPE3
// I2SCDCLK - GPE2
// I2SSCLK - GPE1
// I2SLRCLK - GPE0
//
// charlie
v_pIOPregs->rGPEUP |= DISABLE_I2S_PULLUPS;
v_pIOPregs->rGPECON |= (ENABLE_I2SSDO | ENABLE_I2SSDI | ENABLE_I2SCDCLK | ENABLE_I2SSCLK | ENABLE_I2SLRCLK);
// Port Init for IIS
//v_pIOPregs->rGPEUP |= 0x1f;
//PG[4:0]=I2SSDI:I2SSDO:CDCLK:I2SSCLK:I2SLRCK
//v_pIOPregs->rGPECON = ((v_pIOPregs->rGPECON & 0xfffffc00) | 0x2aa);
//----- 3. Configure the I2S controller with reasonable default values -----
// v_pIISregs->rIISCON = (TRANSMIT_DMA_REQUEST_ENABLE | RECEIVE_DMA_REQUEST_ENABLE | IIS_PRESCALER_ENABLE);
// charlie
v_pIISregs->rIISCON = (TRANSMIT_DMA_REQUEST_ENABLE | IIS_PRESCALER_ENABLE);
//---------------------------------------------------------------------------------------------------------
// On SMDK2410 board, Audio codec left/right outputs are mis-connected to a stereo headphone jack.
// So, I define that active level of left/right channel is "HIGH for left channel" (ACTIVE_CHANNEL_RIGHT).
//---------------------------------------------------------------------------------------------------------
//v_pIISregs->rIISMOD = ( IIS_SLAVE_MODE | IIS_TRANSMIT_RECEIVE_MODE | ACTIVE_CHANNEL_LEFT
//v_pIISregs->rIISMOD = ( IIS_SLAVE_MODE | IIS_TRANSMIT_RECEIVE_MODE | ACTIVE_CHANNEL_RIGHT
v_pIISregs->rIISMOD = ( IIS_MASTER_MODE | IIS_TRANSMIT_RECEIVE_MODE | ACTIVE_CHANNEL_LEFT
//| SERIAL_INTERFACE_IIS_COMPAT | DATA_16_BITS_PER_CHANNEL
|SERIAL_INTERFACE_MSBL_COMPAT| DATA_16_BITS_PER_CHANNEL
| MASTER_CLOCK_FREQ_384fs | SERIAL_BIT_CLOCK_FREQ_32fs );
//| MASTER_CLOCK_FREQ_256fs | SERIAL_BIT_CLOCK_FREQ_32fs );
//---------------------------------------------------------------------------------------------------------
//v_pIISregs->rIISMOD = ( MASTER_CLOCL_MPLLIN | IIS_MASTER_MODE | /*IIS_TRANSMIT_RECEIVE_MODE |*/ ACTIVE_CHANNEL_RIGHT /*ACTIVE_CHANNEL_LEFT*/
//| SERIAL_INTERFACE_MSBL_COMPAT/*SERIAL_INTERFACE_IIS_COMPAT*/ | DATA_16_BITS_PER_CHANNEL
//| MASTER_CLOCK_FREQ_384fs | SERIAL_BIT_CLOCK_FREQ_32fs);
// | MASTER_CLOCK_FREQ_256fs | SERIAL_BIT_CLOCK_FREQ_32fs );
v_pIISregs->rIISFCON = ( TRANSMIT_FIFO_ACCESS_DMA | TRANSMIT_FIFO_ENABLE );
SetI2SClockRate(IS2LRCLK_44100);
//SetI2SClockRate(IS2LRCLK_48000);
//SetI2SClockRate(IS2LRCLK_32000);
//----- 4. For power management purposes, shut the clocks off! -----
StopI2SClock();
// charlie
v_pIISregs->rIISCON |= IIS_INTERFACE_ENABLE; // Enable the I2S clock
RETAILMSG(1,(TEXT("IIS init finish!\r\n")));
return TRUE;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: I2S_Deinit()
Description: Deinitializes the I2S bus and controller.
Notes: This routine DOES NOT unmap the control registers;
the caller is responsible for freeing this memory.
Returns: Boolean indicating success.
-------------------------------------------------------------------*/
BOOL I2S_Deinit()
{
//----- 1. Stop the I2S clocks -----
StopI2SClock();
return TRUE;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: I2S_WriteData()
Description: Outputs the specified data onto the I2S bus.
Notes: This routine expects that the I2S clock is already
running when it is called.
Returns: Boolean indicating success.
-------------------------------------------------------------------*/
BOOL I2S_WriteData(LPWORD lpBuff, DWORD dwLen)
{
static DWORD waitCount = 0;
static DWORD i = 0;
//----- 1. Check the parameters -----
if(!lpBuff || (dwLen == 0))
{
DEBUGMSG(ZONE_ERROR, (TEXT("WAVEDEV.DLL:I2S_WriteData() - Invalid parameters!\r\n")));
goto WRITE_ERROR;
}
// StartI2SClock();
//----- 2. Enable the transmit FIFO -----
v_pIISregs->rIISFCON |= TRANSMIT_FIFO_ENABLE;
//----- 3. Write all of the bytes in the input buffer onto the I2S bus -----
while(dwLen)
{
//----- 4. Write a FIFO's worth of data out onto the I2S bus -----
if(dwLen > MAX_TRANSMIT_FIFO_ENTRIES)
{
i = MAX_TRANSMIT_FIFO_ENTRIES;
}else
{
i = dwLen;
}
dwLen -= i;
while(i--);
{
v_pIISregs->rIISFIF = *lpBuff++;
}
}
StopI2SClock();
return TRUE;
WRITE_ERROR:
StopI2SClock();
return FALSE;
}
//------------------------------------ Helper Routines ------------------------------------
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: StartI2SClock()
Description: Enables the I2S clock that drives the audio codec chip.
Returns: N/A
-------------------------------------------------------------------*/
VOID StartI2SClock(VOID)
{
return;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: StopI2SClock()
Description: Disables the I2S clock that drives the audio codec chip.
Returns: N/A
-------------------------------------------------------------------*/
VOID StopI2SClock(VOID)
{
// v_pIISregs->rIISCON &= ~IIS_INTERFACE_ENABLE; // Disable the I2S clock
// charlie
// g_pCLKPWRreg->rCLKCON &= ~IIS_INTERNAL_CLOCK_ENABLE; // Disable the CPU clock to the SPI controller
return;
}
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: SetI2SClockRate()
Description: Sets the I2S clock that drives the audio codec chip:
Params: ClockRate IS2LRCLK_800 800 Khz
IS2LRCLK_11025 11025 Khz
IS2LRCLK_16000 16000 Khz
IS2LRCLK_22050 22050 Khz
IS2LRCLK_32000 32000 Khz
IS2LRCLK_44100 44100 Khz
IS2LRCLK_48000 48000 Khz
IS2LRCLK_64000 64000 Khz
IS2LRCLK_88200 88200 Khz
IS2LRCLK_96000 96000 Khz
Returns: N/A
-------------------------------------------------------------------*/
VOID SetI2SClockRate(DWORD ClockRate)
{
BYTE prescaler;
DWORD codeclock, i2scdclk;
//----- 1. Set the clock rate -----
// FORMAT: bits[9:5] - Prescaler Control A
// bits[4:0] - Prescaler Control B
//
// Range: 0-31 and the division factor is N+1 (a.k.a. 1-32)
//
// The I2SLRCLK frequency is determined as follows:
//
// I2SLRCLK = CODECLK / I2SCDCLK and (prescaler+1) = PCLK / CODECLK
//
// Thus, rearranging the equations a bit we can see that:
//
// prescaler = (PCLK / CODECLK) - 1
// or
// prescaler = ((PCLK / (IS2LRCLK * IS2CDCLK)) - 1
//
// NOTE: The following formula is actually used in order to avoid floating point arithmetic:
//
// prescaler = ((PCLK + ((IS2LRCLK * IS2CDCLK) - 1)) / (IS2LRCLK * IS2CDCLK)) - 1
//
if(v_pIISregs->rIISMOD & MASTER_CLOCK_FREQ_384fs)
{
i2scdclk = 384; // Sampling frequency
}else
{
i2scdclk = 256; // Sampling frequency
}
codeclock = ClockRate * i2scdclk;
prescaler = (BYTE)((S2440PCLK + (codeclock - 1)) / codeclock) - 1;
// RETAILMSG(1,(TEXT("Prescaler:%d\n"),prescaler));
//----- IMPORTANT: Make sure we set both channel prescalers to the same value (see datasheet for details) -----
v_pIISregs->rIISPSR = ((prescaler << 5) + prescaler);
return;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -