📄 i2s_test.c
字号:
/**************************************************************************************
*
* Project Name : S3C6400 Validation
*
* Copyright 2006 by Samsung Electronics, Inc.
* All rights reserved.
*
* Project Description :
* This software is only for validating functions of the S3C6400.
* Anybody can use this software without our permission.
*
*--------------------------------------------------------------------------------------
*
* File Name : i2s_test.c
*
* File Description : This file implements i2s test functions.
*
* Author : Sunil,Roe
* Dept. : AP Development Team
* Created Date : 2006/12/26
* Version : 0.1
*
* History
* - Created(Sunil,Roe 2006/12/26)
*
**************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "def.h"
#include "option.h"
#include "library.h"
#include "sfr6400.h"
#include "system.h"
#include "sysc.h"
#include "gpio.h"
#include "dma.h"
#include "intc.h"
#include "iic.h"
#include "i2s.h"
#define I2S0 0
#define I2S1 1
// global variables
u8 g_ucI2SPortNum;
volatile I2S_oInform g_oaI2SInform[I2S_CONNUM];
static DMAC oI2SDma;
/*---------------------------------- ISR Routines Definition ---------------------------------*/
void __irq ISR_I2CINT(void);
void __irq ISR_DMARecDone(void);
void __irq ISR_DMAPlayDone(void);
/*---------------------------------- Function Definition ---------------------------------*/
void I2S_Test(void);
bool I2S_Init(u8);
void I2S_InitPort(u8);
void I2S_ReturnPort(u8);
void I2S_LoopBackTest(void);
void I2S_PlayWaveInPolling(void);
void I2S_PlayWaveInDMA(void);
void I2S_PlayWaveInDMASlave(void);
void I2S_PlayWaveUsingPolling(u8 , u32 *, u32);
void I2S_PlayWaveUsingDMA(u8, u32 *, u32);
void I2S_RecordInPolling(void);
void I2S_RecordUsingPolling(u8 , u32 *, u32);
void I2S_SelectCDCLK(u8, eI2S_CODEC_MODE);
void I2S_SelectPCLK(u8);
void I2S_SelectEXTCLK(u8);
void I2S_SelectEPLL(u8);
void I2S_SelectMPLL(u8);
void I2S_SelectSysExtCLK(u8);
void I2S_RecordSoundViaLineInPlayIt(void);
void I2S_RecordSoundViaMICInPlayIt(void);
void I2S_RecSoundUsingDMA(u8, u8, u32);
u32 I2S_GetBFS(u8);
u32 I2S_GetRFS(u8);
extern void Test_CLKOUT(void) ;
extern void SYSCT_Clock(void);
extern volatile u32 g_iSeed, g_iNum, g_iARMCLK_DIVN_R, g_iHCLKx2_DIVN_R, g_iPCLK_DIVN_R;
/*---------------------------------- Init Functions ---------------------------------*/
//////////
// Function Name : I2S_Init
// Function Description : This function initializes a certain I2S Port.
// Input : uPort - I2S Port Number
// Output : TRUE - Memory Device is reset
// FALSE - Memory Device is not reset because of ERROR
// Version : v0.1
bool I2S_Init(u8 ucCon)
{
u32 uBaseAddress;
if(ucCon == I2S0)
{
uBaseAddress = I2S0_BASE;
// using DMAC0
#ifdef I2S_NORMAL_DMA
g_oaI2SInform[ucCon].ucDMANum = NUM_DMA0;
g_oaI2SInform[ucCon].ucDMACon = DMA0;
g_oaI2SInform[ucCon].ucDMATxSrc = DMA0_I2S0_TX;
g_oaI2SInform[ucCon].ucDMARxSrc = DMA0_I2S0_RX;
SYSC_SelectDMA(eSEL_I2S0_TX, 1);
SYSC_SelectDMA(eSEL_I2S0_RX, 1);
#else // I2S_SECURE_DMA
g_oaI2SInform[ucCon].ucDMANum = NUM_SDMA0;
g_oaI2SInform[ucCon].ucDMACon = SDMA0;
g_oaI2SInform[ucCon].ucDMATxSrc = DMA0_I2S0_TX;
g_oaI2SInform[ucCon].ucDMARxSrc = DMA0_I2S0_RX;
SYSC_SelectDMA(eSEL_I2S0_TX, 0);
SYSC_SelectDMA(eSEL_I2S0_RX, 0);
#endif
}
else if(ucCon == I2S1)
{
uBaseAddress = I2S1_BASE;
// using DMAC1
#ifdef I2S_NORMAL_DMA
g_oaI2SInform[ucCon].ucDMANum = NUM_DMA1;
g_oaI2SInform[ucCon].ucDMACon = DMA1;
g_oaI2SInform[ucCon].ucDMATxSrc = DMA1_I2S1_TX;
g_oaI2SInform[ucCon].ucDMARxSrc = DMA1_I2S1_RX;
SYSC_SelectDMA(eSEL_I2S1_TX, 1);
SYSC_SelectDMA(eSEL_I2S1_RX, 1);
#else
g_oaI2SInform[ucCon].ucDMANum = NUM_SDMA1;
g_oaI2SInform[ucCon].ucDMACon = SDMA1;
g_oaI2SInform[ucCon].ucDMATxSrc = DMA1_I2S1_TX;
g_oaI2SInform[ucCon].ucDMARxSrc = DMA1_I2S1_RX;
SYSC_SelectDMA(eSEL_I2S1_TX, 0);
SYSC_SelectDMA(eSEL_I2S1_RX, 0);
#endif
}
else
{
return FALSE;
}
I2S_SetBaseAddr(ucCon, uBaseAddress);
g_oaI2SInform[ucCon].puRecBuf = (u32 *)(_DRAM_BaseAddress+0x01000000*(ucCon+1));
I2S_InitPort(ucCon);
return TRUE;
}
//////////
// Function Name : I2S_InitPort
// Function Description :
// This function Initialize ports as I2S.
// Input : uPort - I2S port number
// Output : NONE
// Version :
void I2S_InitPort(u8 ucPort)
{
switch(ucPort)
{
case 0 :
GPIO_SetFunctionAll(eGPIO_D, 0x33333, 0x0);
GPIO_SetPullUpDownAll(eGPIO_D, 0x22222); // pull-up/down disable
break;
case 1 :
GPIO_SetFunctionAll(eGPIO_E, 0x33333, 0x0);
GPIO_SetPullUpDownAll(eGPIO_E, 0x22222); // pull-up/down disable
break;
default :
GPIO_SetFunctionAll(eGPIO_D, 0x33333, 0x0);
GPIO_SetPullUpDownAll(eGPIO_D, 0x22222); // pull-up/down disable
break;
}
}
//////////
// Function Name : I2S_ReturnPort
// Function Description :
// This function Initialize ports as default GPIO(input).
// Input : uPort - I2S port number
// Output : NONE
// Version :
void I2S_ReturnPort(u8 ucPort)
{
switch(ucPort)
{
case 0 :
GPIO_SetFunctionAll(eGPIO_D, 0x0, 0x0);
break;
case 1 :
GPIO_SetFunctionAll(eGPIO_E, 0x0, 0x0);
break;
default :
GPIO_SetFunctionAll(eGPIO_D, 0x0, 0x0);
break;
}
}
//////////
// Function Name : I2S_Init8753
// Function Description :
// This function prepares the initialization of WM8753
// Input :
// ucPort - I2S Port Number
// ucMode - I2S Operation Mode
// ucStatus -I2S Operation Status
// Output : NONE
// Version :
void I2S_Init8753(u8 ucPort, u8 ucMode, u8 ucStatus, eI2S_CODEC_MODE eCodecMode)
{
IIC_Open(100000);
I2S_Init8753Driver(ucPort, ucMode, ucStatus, eCodecMode);
IIC_Close();
}
/*---------------------------------- ISR Routines ---------------------------------*/
//////////
// Function Name : ISR_DMA1INTRecDone
// Function Description : This function implements ISR of DMA Record Interrupt.
// Input : NONE
// Output : NONE
// Version : v0.1
void __irq ISR_DMARecDone(void)
{
INTC_Disable(g_oaI2SInform[g_ucI2SPortNum].ucDMANum);
// Interrupt Clear
DMACH_ClearIntPending(&oI2SDma);
DMACH_ClearErrIntPending(&oI2SDma);
I2S_SetDMAActive(g_ucI2SPortNum, eI2S_XFER_RX, INACTIVE);
I2S_SetActive(g_ucI2SPortNum, INACTIVE);
g_oaI2SInform[g_ucI2SPortNum].uRecCount++;
Disp(".");
#if 0
I2S_SetDMAActive(g_ucI2SPortNum, eI2S_XFER_RX, ACTIVE);
I2S_SetActive(g_ucI2SPortNum, ACTIVE);
if(g_oaI2SInform[g_ucI2SPortNum].uRecCount < I2S_DMAC0_REC_COUNT)
{
DMACH_Setup(DMA_A, 0x0, I2S_GetRegAddr(g_ucI2SPortNum,eI2S_TXD), 1, (u32)(g_oaI2SInform[g_ucI2SPortNum].puRecBuf + I2S_RECORD_LENGTH), 0, WORD, I2S_DMA_TRANSFER_SIZE, DEMAND, (DREQ_SRC)(g_oaI2SInform[g_ucI2SPortNum].ucDMATxSrc), MEM, SINGLE, &oI2SDma);
INTC_Enable(g_oaI2SInform[g_ucI2SPortNum].ucDMANum);
}
else
{
g_oaI2SInform[g_ucI2SPortNum].ucRecDone = 1;
}
INTC_Enable(g_oaI2SInform[g_ucI2SPortNum].ucDMANum);
#endif
g_oaI2SInform[g_ucI2SPortNum].ucRecDone = 1;
INTC_ClearVectAddr();
}
//////////
// Function Name : ISR_DMA1INTPlayDone
// Function Description : This function implements ISR of DMA Play Interrupt.
// Input : NONE
// Output : NONE
// Version : v0.1
void __irq ISR_DMAPlayDone(void)
{
Disp("\n TX DMA ISR ~~~\n");
INTC_Disable(g_oaI2SInform[g_ucI2SPortNum].ucDMANum);
// Interrupt Clear
DMACH_ClearIntPending(&oI2SDma);
DMACH_ClearErrIntPending(&oI2SDma);
#if 0
I2S_SetDMAActive(g_ucI2SPortNum, eI2S_XFER_TX, INACTIVE);
I2S_SetActive(g_ucI2SPortNum, INACTIVE);
I2S_SetDMAActive(g_ucI2SPortNum, eI2S_XFER_TX, ACTIVE);
I2S_SetActive(g_ucI2SPortNum, ACTIVE);
#else
// DMACH_Setup(DMA_B, 0x0, (u32)ucStartAddr , 0, I2S_GetRegAddr(ucCon,eI2S_TXD), 1, WORD, I2S_RECORD_LENGTH/4, DEMAND, MEM, (DREQ_SRC)(g_oaI2SInform[ucCon].ucDMATxSrc), SINGLE, &oI2SDma);
// DMACH_AddrSetup(DMA_B, (u32)g_oaI2SInform[g_ucI2SPortNum].puRecBuf, I2S_GetRegAddr(g_ucI2SPortNum,eI2S_TXD), &oI2SDma);
DMACH_Setup(DMA_B, 0x0, (u32)g_oaI2SInform[g_ucI2SPortNum].puRecBuf, 0, I2S_GetRegAddr(g_ucI2SPortNum,eI2S_TXD), 1, WORD, g_oaI2SInform[g_ucI2SPortNum].uRecLength, DEMAND, MEM, (DREQ_SRC)(g_oaI2SInform[g_ucI2SPortNum].ucDMATxSrc), SINGLE, &oI2SDma);
#endif
Disp("\n TX DMA Done ~~~\n");
DMACH_Start(&oI2SDma);
I2S_SetActive(g_ucI2SPortNum, INACTIVE);
I2S_SetActive(g_ucI2SPortNum, ACTIVE);
INTC_Enable(g_oaI2SInform[g_ucI2SPortNum].ucDMANum);
INTC_ClearVectAddr();
}
/*---------------------------------- Test Functions -------------------------------*/
//////////
// Function Name : I2S_LoopBackTest
// Function Description :
// This function implements I2S Loopback Test function.
// To execute this test, SMDK6400 must be modified.
// After eliminating U32 and U35 on the bottom plate, I2S signal line should be connected directly.
// U32 U35
// pin3 (BCLK) pin3 (BCLK)
// pin7 (CDCLK) pin7 (CDCLK) --> These signal should be connected to R249.(Ext.Clock)
// pin11(LRCK) pin11(LRCK)
// pin17(DI) pin21(DO)
// pin21(DO) pin17(DI)
//
// Master - I2S0 (Master sends LRCK and BCLK to Slave port.)
// Slave - I2S1
// CDCLK - External Clock
// Input : NONE
// Output : NONE
// Version :
void I2S_LoopBackTest(void)
{
u32 uLoopCnt = 0;
u8 ucExitKey=0;
u8 ucCODECLK=0;
u8 ucBCLK=0;
u8 ucBLTH=0;
u32 uCODECFS = 0;
u32 uBCLKFS = 0;
u32 uPcmTxDataSize = 0xC00;
u32 uPcmRxDataSize = 0xC00;
u32 uRegValue = 0;
Disp("\n = Loop Back Test =.\n");
Disp(" Note. To execute this test, SMDK6400 must be modified.\n");
Disp(" After eliminating U32 and U35 on the bottom plate, I2S signal line should be connected directly.\n");
I2S_FlushFIFO(I2S0, eI2S_FLUSH_TX, FLUSH);
I2S_FlushFIFO(I2S0, eI2S_FLUSH_TX, NON_FLUSH);
I2S_FlushFIFO(I2S1, eI2S_FLUSH_RX, FLUSH);
I2S_FlushFIFO(I2S1, eI2S_FLUSH_RX, NON_FLUSH);
// Set up the tx buf.
for (uLoopCnt = 0; uLoopCnt<uPcmTxDataSize; uLoopCnt++)
*(u8 *)((u8 *)g_oaI2SInform[I2S0].puRecBuf+uLoopCnt) = (u8)(uLoopCnt+2)%0xff;
// Clear the rx buf.
for (uLoopCnt = 0; uLoopCnt<uPcmRxDataSize; uLoopCnt++)
*(u8 *)((u8 *)g_oaI2SInform[I2S1].puRecBuf+uLoopCnt) = 0;
// select freq.
Disp("\n Root Frequency Sample ( 0:256fs 1:512fs 2:384fs(D) 3:768fs ) = ");
ucCODECLK = GetIntNum();
if (ucCODECLK == 0xff ) ucCODECLK = 2;
uCODECFS = I2S_GetRFS(ucCODECLK);
Disp("\n Bit Frequency Sample (0:32fs 1:48fs(D) 2:16fs 3:24fs) = ");
ucBCLK = GetIntNum();
if (ucBCLK == 0xff ) ucBCLK = 1;
uBCLKFS = I2S_GetBFS(ucBCLK);
Disp("\n BLC (0: 16bit(D) 1:8bit ) = ");
ucBLTH = GetIntNum();
if (ucBLTH == 0xff ) ucBLTH = 0;
Disp("\nuBCLKFS:%d, uCODECFS:%d", uBCLKFS, uCODECFS);
Disp("\nI2S Bit Clock = %4.4f MHz", g_oaI2SInform[g_ucI2SPortNum].fI2SCodecCLK*uBCLKFS/uCODECFS/1000000);
Disp("\nI2S Sampling Rate = %4.4f kHz\n", g_oaI2SInform[g_ucI2SPortNum].fI2SCodecCLK/uCODECFS/1000);
//------------ Master Configuration ------------
I2S_SelectCDCLK(I2S0, eI2S_CODEC_SLAVE_MODE);
// rI2SCON : TxDMA
I2S_SetI2STxerMode(I2S0, eI2S_XFER_TX);
// rI2SMOD : TxOnlyMode, I2SRootClk, BitClk, BitLength
I2S_SetInterfaceMode(I2S0, eI2S_XFER_TX, eLEFT_LOW_RIGHT_HIGH, eI2S_DATA_I2S, ucCODECLK, ucBCLK, ucBLTH);
I2S_FlushFIFO(I2S0, eI2S_FLUSH_TX, FLUSH); // rI2SFIC : TxFIFO Flush(15)
I2S_FlushFIFO(I2S0, eI2S_FLUSH_TX, NON_FLUSH); // rI2SFIC : TxFIFO No Flush(15)
//------------ Slave Configuration ------------
//IIS Pre-scaler Setting
I2S_SetPreScaler(I2S1, ENABLE, 2);
// IIS CDCLKCON
I2S_SetCodecClkSrc(I2S1, eI2S_CLK_EXTERNAL);
//IIS Master mode selection
I2S_SetMasterSlaveMode(I2S1, eI2S_MS_SLAVE_MODE_USING_PCLK);
// rI2SCON : RxDMA
I2S_SetI2STxerMode(I2S1, eI2S_XFER_RX);
// rI2SMOD : RxOnlyMode, I2SRootClk, BitClk, BitLength
I2S_SetInterfaceMode(I2S1, eI2S_XFER_RX, eLEFT_LOW_RIGHT_HIGH, eI2S_DATA_I2S, ucCODECLK, ucBCLK, ucBLTH);
I2S_FlushFIFO(I2S1, eI2S_FLUSH_RX, FLUSH); // rI2SFIC : RxFIFO Flush(7)
I2S_FlushFIFO(I2S1, eI2S_FLUSH_RX, NON_FLUSH); // rI2SFIC : RxFIFO No Flush(7)
//----Step 1. Data should be transmitted from I2S0 to I2S1 in 16 times before I2S0 is activated.
uRegValue = I2S_GetRegValue(I2S0, eI2S_CON);
while(!(uRegValue&(1<<8))) {
I2S_SetRegValue(I2S0, eI2S_TXD, *g_oaI2SInform[I2S0].puRecBuf++);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -