www.pudn.com > ADS_s3c2440a.rar > ac97.c
/*******************************************************************************
File Name: AC97.c
Description: S3C2440A AC97 Controller Function Test Code
Version: 0.2
History:
0.0: First draft
0.1: 2003. 12. 22, Following test codes were modified by Yoh-Han Lee
- AC97 PCM Out in DMA mode
- AC97 PCM In in DMA mode
0.2: 2004. 02. 12, Programmed and tested by Yoh-Han Lee
- Volume up/down and Mute on/off are available, when codec plays PCM data.
- AC97 power down mode test is supported.
- AC97 reset timing check is added.
- Variable ADC/DAC Selection is supported.
- AC97 PCM Out in the interrupt mode is supported. Thanks to Y. M. Lee.
- AC97 PCM In using interrupt mode is supported.
- AC97 MIC In using interrupt or DMA is added.
********************************************************************************/
#include
#include
#include "option.h"
#include "2440addr.h"
#include "2440lib.h"
#include "def.h"
#include "ac97.h"
#define AC97_REC_LEN 0xfffff*4
#define DOWN_BUF _NONCACHE_STARTADDRESS
#define PCM_OUT_TRIGGER 8
#define PCM_IN_TRIGGER 8
#define AC97_PCM_OUT_THRESHOLD (1<<18)
#define AC97_PCM_IN_THRESHOLD (1<<17)
#define AC97_MIC_IN_THRESHOLD (1<<16)
U32 save_AC97_rGPECON, save_AC97_rGPEDAT, save_AC97_rGPEUP;
U32 AC97_size, AC97_fs;
U32 Output_Volume,Input_Volume;
U32 *Rec_AC97_BUF, *Play_AC97_BUF, *End_AC97_BUF;
static int delayLoopCount;
S16 PCM_Out_INT_Exit = 0;
S16 PCM_In_INT_Exit =0;
U8 *AC97_BUF,*AC97_temp;
U8 Up_Down_Volume;
char AC97_Rec_Done = 0;
char Codec_Ready_Irq;
char AC97_mute = 1;
char Codec_Ready = 1;
void AC97_Port_Init(void);
void AC97_Port_Return(void);
void AC97_Init(void);
void Download_PCM_File(void);
void AC97_CodecInit_PCMOut(U16 AC97_fs);
void AC97_CodecInit_PCMIn(U16 AC97_fs);
void AC97_CodecInit_MICIn(U16 AC97_fs);
void AC97_CodecInit_PD(void);
void AC97_CodecExit_PCMOut(void);
void AC97_CodecExit_PCMIn(U16 DACs_off);
void AC97_CodecExit_MICIn(U16 DACs_off);
void AC97_PCMout_DMA1(U32 PCM_Size);
void AC97_PCMout_INT(U32 PCM_Size);
void AC97_PCMin_DMA2(U32 PCM_Size);
void AC97_PCMin_INT(U32 PCM_Size);
void AC97_MICin_DMA3(U32 MIC_Size);
void AC97_MICin_INT(U32 PCM_Size);
void Delay_Init(void);
void PCM_In_Volume( U8 Up_Down_Volume);
void PCM_Out_Volume( U8 Up_Down_Volume);
void AC97_Controller_State(void);
void Delay_After_CommandWrite(int time);
U16 AC97_Select_SamplingRate(void);
U16 AC97_Codec_Cmd(U8 CMD_Read, U8 CMD_Offset, U16 CMD_Data);
static void __irq DMA1_Play_Done(void);
static void __irq DMA2_Rec_Done(void);
static void __irq DMA3_Rec_Done(void);
static void __irq RxInt(void);
static void __irq Muting(void);
void __irq AC97_Codec_Ready(void);
void __irq Irq_AC97_PCMout(void);
void __irq Irq_AC97_PCMin(void);
void __irq Irq_AC97_MICin(void);
void * func_ac97_test[][2]=
{
//AC97 Function Test Item
(void *)PCMout_Test_AC97, "Play Wave File ",
(void *)PCMin_Test_AC97, "Record Sound via LineIn and Play it ",
(void *)MICin_Test_AC97, "Record Voice via MIC and Play it ",
(void *)Powerdown_Test_AC97, "AC97 Power Down ",
(void *)Reset_Test_AC97, "AC97 Reset Timing Check ",
0,0
};
void AC97_Test(void)
{
int i;
AC97_Port_Init();
while(1)
{
i=0;
Uart_Printf("\n\n==================== AC97 Function Test ====================\n\n");
while(1)
{ //display menu
Uart_Printf("%2d:%s",i,func_ac97_test[i][1]);
i++;
if((int)(func_ac97_test[i][0])==0)
{
Uart_Printf("\n");
break;
}
if((i%2)==0)
Uart_Printf("\n");
}
Uart_Printf("\n============================================================");
Uart_Printf("\nSelect #Item or Press enter key to exit:");
i = Uart_GetIntNum();
if(i==-1) break; // return.
if(i>=0 && (i<((sizeof(func_ac97_test)-1)/8)) ) // select and execute...
( (void (*)(void)) (func_ac97_test[i][0]) )();
}
rAC_GLBCTRL = 0;
}
void PCMout_Test_AC97(void)
{
int i;
//U8 Char;
AC97_Port_Init();
Delay(1000);
//Uart_Printf("Download PCM Wave File? (y/n)");
//Char=Uart_Getch();
//if( (Char == 'y') | (Char == 'Y') )
Download_PCM_File();
AC97_Init();
if(Codec_Ready)
{
Uart_Printf("\nSelect PCM Out Operation Mode\n");
Uart_Printf("0: Interrupt, 1: DMA\n");
i = Uart_GetIntNum();
AC97_CodecInit_PCMOut(AC97_fs);
switch(i)
{
case 0:
AC97_PCMout_INT(AC97_size);
break;
case 1:
AC97_PCMout_DMA1(AC97_size);
break;
default:
AC97_PCMout_DMA1(AC97_size);
break;
}
AC97_CodecExit_PCMOut();
}
AC97_mute = 1;
Codec_Ready =1;
PCM_Out_INT_Exit = 0;
AC97_Port_Return();
}
void PCMin_Test_AC97(void)
{
int i;
U32 Sampling_Rate;
AC97_Rec_Done = 0;
AC97_Port_Init();
Sampling_Rate = AC97_Select_SamplingRate();
AC97_Init();
if(Codec_Ready)
{
Uart_Printf("\nSelect PCM In/Out Operation Mode\n");
Uart_Printf("0: Interrupt, 1: DMA\n");
i = Uart_GetIntNum();
AC97_CodecInit_PCMIn(Sampling_Rate);
switch(i)
{
case 0:
AC97_PCMin_INT(AC97_REC_LEN);
//Play Recorded Data
AC97_CodecInit_PCMOut(Sampling_Rate);
AC97_PCMout_INT(AC97_REC_LEN);
break;
case 1:
AC97_PCMin_DMA2(AC97_REC_LEN);
//Play Recorded Data
AC97_CodecInit_PCMOut(Sampling_Rate);
AC97_PCMout_DMA1(AC97_REC_LEN);
break;
default:
AC97_PCMin_DMA2(AC97_REC_LEN);
//Play Recorded Data
AC97_CodecInit_PCMOut(Sampling_Rate);
AC97_PCMout_DMA1(AC97_REC_LEN);
break;
}
AC97_CodecExit_PCMIn(1);
}
Codec_Ready =1;
AC97_mute = 1;
PCM_Out_INT_Exit = 0;
PCM_In_INT_Exit = 0;
AC97_Port_Return();
}
void MICin_Test_AC97(void)
{
U16 i, Sampling_Rate;
AC97_Rec_Done = 0;
AC97_Port_Init();
Delay(1000);
Sampling_Rate = AC97_Select_SamplingRate();
AC97_Init();
if(Codec_Ready)
{
Uart_Printf("\nSelect MIC In Operation Mode\n");
Uart_Printf("0: Interrupt, 1: DMA\n");
i = Uart_GetIntNum();
AC97_CodecInit_MICIn(Sampling_Rate);
switch(i)
{
case 0:
AC97_MICin_INT(AC97_REC_LEN/2);
//Play Recorded Data
AC97_CodecInit_PCMOut(Sampling_Rate);
AC97_PCMout_DMA1(AC97_REC_LEN/2);
break;
case 1:
AC97_MICin_DMA3(AC97_REC_LEN/2);
//Play Recorded Data
AC97_CodecInit_PCMOut(Sampling_Rate);
AC97_PCMout_DMA1(AC97_REC_LEN/2);
break;
default:
AC97_MICin_DMA3(AC97_REC_LEN/2);
//Play Recorded Data
AC97_CodecInit_PCMOut(Sampling_Rate);
AC97_PCMout_DMA1(AC97_REC_LEN/2);
break;
}
AC97_CodecExit_MICIn(1);
}
Codec_Ready =1;
AC97_mute = 1;
PCM_In_INT_Exit = 0;
AC97_Port_Return();
}
void Powerdown_Test_AC97(void)
{
int i;
AC97_Port_Init();
Delay(1000);
AC97_Init();
if(Codec_Ready)
{
AC97_CodecInit_PD();
//Normal
Uart_Printf("\nNormal\n");
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//ADCs off
Uart_Printf("\n=>ADCs off PR0\n");
AC97_Codec_Cmd(0,0x26,(1<<8));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//DACs off
Uart_Printf("\n=>DACs off PR1\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Analog off
Uart_Printf("\n=>Analog off PR2\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Digital I/F off
Uart_Printf("\n=>Digital I/F off PR4\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
AC97_Controller_State();
//Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Shut off AC-Link
Uart_Printf("\n=>Shut off AC-Link\n");
rAC_GLBCTRL &= ~(1<<2);
AC97_Controller_State();
//Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
while(1)
{
Uart_Printf("\nPress enter key for Warm Reset");
i = Uart_GetIntNum();
if(i==-1) break;
}
//Warm Reset
Uart_Printf("\n=>Warm Reset\n");
rAC_GLBCTRL = (1<<1);
AC97_Controller_State();
rAC_GLBCTRL &= ~(1<<1);
rAC_GLBCTRL |= (1<<2);
AC97_Controller_State();
rAC_GLBCTRL |= (1<<3);
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Cold Reset
Uart_Printf("\n=>Cold Reset\n");
rAC_GLBCTRL |= (1<<0);
AC97_Controller_State();
rAC_GLBCTRL &= ~(1<<0);
rAC_GLBCTRL |= (1<<2);
AC97_Controller_State();
rAC_GLBCTRL |= (1<<3);
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
Codec_Ready =1;
AC97_Port_Return();
}
void Reset_Test_AC97(void)
{
int i;
AC97_Port_Init();
Delay(1000);
AC97_Init();
if(Codec_Ready)
{
AC97_CodecInit_PD();
//Normal
Uart_Printf("\nNormal\n");
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//ADCs off
Uart_Printf("\n=>ADCs off PR0\n");
AC97_Codec_Cmd(0,0x26,(1<<8));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//DACs off
Uart_Printf("\n=>DACs off PR1\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Analog off
Uart_Printf("\n=>Analog off PR2\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Digital I/F off
Uart_Printf("\n=>Digital I/F off PR4\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
AC97_Controller_State();
//Shut off AC-Link
Uart_Printf("\n=>Shut off AC-Link\n");
rAC_GLBCTRL &= ~(1<<2);
//AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
AC97_Controller_State();
//Warm Reset Timing Check
Uart_Printf("\nWarm Reset Timing Check...");
Uart_Printf("\n Probe SYNC and BIT_CLK.");
Uart_Printf("\n Trigger SYNC Rising Edge.");
while(1)
{
Uart_Printf("\nPress enter key for Warm Reset Timing Check...");
i = Uart_GetIntNum();
if(i==-1) break;
}
Uart_Printf("\n=>Warm Reset\n");
rAC_GLBCTRL = (1<<1);
AC97_Controller_State();
rAC_GLBCTRL &= ~(1<<1);
rAC_GLBCTRL |= (1<<2);
AC97_Controller_State();
rAC_GLBCTRL |= (1<<3);
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat Reg. Value (at 0x26): 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
Uart_Printf("\nPress any key.\n");
Uart_Getch();
//Cold Reset Timing Check
Uart_Printf("\nCold Reset Timing Check...");
Uart_Printf("\n Probe RESET#, BIT_CLK and SDATA_IN.");
Uart_Printf("\n Trigger RESET# Rising Edge.");
while(1)
{
Uart_Printf("\nPress enter key for Cold Reset Timing Check...");
i = Uart_GetIntNum();
if(i==-1) break;
}
rAC_GLBCTRL = 0x1;
Delay(1000);
rAC_GLBCTRL = 0x0;
Delay(1000);
Uart_Printf("\nPress any key to exit.\n");
Uart_Getch();
}
Codec_Ready =1;
AC97_Port_Return();
}
/* Functional Sub-Routines */
void AC97_Port_Init(void)
{
//Push AC97 GPIO port configuration
save_AC97_rGPEDAT=rGPEDAT;
save_AC97_rGPECON=rGPECON;
save_AC97_rGPEUP=rGPEUP;
//---------------------------------------------------------------------
// PORT E GROUP
//Ports : GPE4 GPE3 GPE2 GPE1 GPE0
//Signal : AC_SDATA_OUT AC_SDATA_IN AC_nRESET AC_BIT_CLK AC_SYNC
//Binary : 11, 11, 11, 11, 11
//---------------------------------------------------------------------
rGPECON = rGPECON & ~(0x3ff) | 0x3ff; //GPE[4:0]=AC_SDATA_OUT AC_SDATA_IN AC_nRESET AC_BIT_CLK AC_SYNC
rGPEUP = rGPEUP & ~(0x1f) | 0x1f; //The pull up function is disabled GPE[4:0] 1 1111
//For EINT0 Push Button
rGPFUP = ((rGPFUP & ~(1<<0)) | (1<<0)); //GPF0
rGPFCON = ((rGPFCON & ~(3<<0)) | (1<<1)); //GPF0=EINT0
rEXTINT0 = ((rEXTINT0 & ~(7<<0)) | (2<<0)); //EINT0=falling edge triggered
}
void AC97_Port_Return(void)
{
//Pop AC97 GPIO port configuration
rGPECON=save_AC97_rGPECON;
rGPEDAT=save_AC97_rGPEDAT;
rGPEUP=save_AC97_rGPEUP;
}
void AC97_Init(void)
{
int i=0;
U8 ch;
Uart_Printf("\nAC97 Initialization...\n");
//Cold Reset
rAC_GLBCTRL = 0x1; // controller and codec cold reset
Delay(1000); // delay for controller safety reset
rAC_GLBCTRL = 0x0; // controller and codec normal mode
Delay(1000);
rAC_GLBCTRL = 0x1;
Delay(1000);
rAC_GLBCTRL = 0x0;
Delay(1000);
//AC-link On
rAC_GLBCTRL = (1<<2);
Delay(1000);
AC97_Controller_State();
//Transfer data enable using AC-link
rAC_GLBCTRL |= (1<<3); // AC97 Data transfer active
Delay(1000);
AC97_Controller_State();
Uart_Printf("\nAC97-Link On...\n");
//Codec Ready Check using Codec Ready Interrupt
Codec_Ready_Irq =0;
pISR_WDT_AC97= (unsigned)AC97_Codec_Ready;
ClearPending(BIT_WDT_AC97);
rSUBSRCPND=(BIT_SUB_AC97);
rINTMSK=~(BIT_WDT_AC97);
rINTSUBMSK=~(BIT_SUB_AC97);
rAC_GLBCTRL |= 0x400000;
while(!Codec_Ready_Irq)
{
Uart_Printf(".");
Delay(3000);
i++;
if(i==20)
break;
}
Uart_Printf("\n");
if(i==20)
{
Uart_Printf("\nAC97 codec is not ready.");
Uart_Printf("\nCheck on connection between 2440A and AC97 Codec.\n");
//Uart_Printf("\nRN1, RN3 and R280 instead of RN2, RN4 and R281 must be used for AC97 link on SMDK2440 Base Board (Rev 0.18).\n");
Uart_Printf("\nBye. ");
Codec_Ready = 0;
}
}
void AC97_CodecInit_PD(void)
{
Uart_Printf("\nAC97 Codec Soft Reset\n");
AC97_Codec_Cmd(0,0x00,0x683F); //Codec Soft Reset : 16bit In/Out (stac9766/67)
Uart_Printf("AC97 Codec 0x26 Reg.: 0x%x\n\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
void AC97_CodecInit_PCMIn( U16 AC97_fs)
{
AC97_Codec_Cmd(0,0x00,0x683F); //codec soft reset
AC97_Codec_Cmd(0,0x2A,0x0001); //variable rate enable
Uart_Printf("VRA Enable(1)/Disable(0): 0x%x\n",(0x1&AC97_Codec_Cmd(1,0x2A,0x0001)));
if(AC97_fs==48000){
//ADC Sampling frequency 48kHz
AC97_Codec_Cmd(0,0x32,0xbb80);
}
else if(AC97_fs==44100){
//ADC Sampling frequency 44.1kHz
AC97_Codec_Cmd(0,0x32,0xac44);
}
else if(AC97_fs==22050){
//ADC Sampling frequency 22.05kHz
AC97_Codec_Cmd(0,0x32,0x5622);
}
AC97_Codec_Cmd(0,0x26,(1<<9)); //all power on except DAC Block
Uart_Printf("\nAC97 Codec 0x26 Reg.: 0x%x\n\n", AC97_Codec_Cmd(1,0x26,0x0000));
AC97_Codec_Cmd(0,0x10,0x1010); //line in volume on
AC97_Codec_Cmd(0,0x6e,0x0000); //All Analog Mode, ADC Input select => left slot3, right slot4
AC97_Codec_Cmd(0,0x1a,0x0505); //record source select => Stereo Mix
AC97_Codec_Cmd(0,0x1c,0x0909); //record gain is initial
AC97_Codec_Cmd(0,0x78,0x0001); //ADC HPF Bypass
AC97_Codec_Cmd(0,0x20,0x0000); //General Reg.
Input_Volume = AC97_Codec_Cmd(1,0x10,0x0000); //Line In volume
}
void AC97_CodecInit_PCMOut( U16 AC97_fs)
{
AC97_Codec_Cmd(0,0x00,0x683F); //codec soft reset
AC97_Codec_Cmd(0,0x2A,0x0001); //variable rate enable
//Uart_Printf("\nVRA Enable(1)/Disable(0): 0x%x\n", (0x1&AC97_Codec_Cmd(1,0x2A,0x0001)));
if(AC97_fs==48000){
//DAC Sampling frequency 48kHz
AC97_Codec_Cmd(0,0x2C,0xbb80);
}
else if(AC97_fs==44100){
//DAC Sampling frequency 44.1kHz
AC97_Codec_Cmd(0,0x2C,0xac44);
}
else if(AC97_fs==22050){
//DAC Sampling frequency 22.05kHz
AC97_Codec_Cmd(0,0x2C,0x5622);
}
AC97_Codec_Cmd(0,0x26, (1<<8)); // all power on except ADC blcok
Uart_Printf("AC97 Codec 0x26 Reg.: 0x%x\n\n", AC97_Codec_Cmd(1,0x26,0x0000));
AC97_Codec_Cmd(0,0x18,0x0000); // PCM out volume on
AC97_Codec_Cmd(0,0x20,0x0000); // general purpose
AC97_Codec_Cmd(0,0x04,0x1A1A); // Aux out(HP out) volume on
Output_Volume = AC97_Codec_Cmd(1,0x04,0x00000); //HP out volume
}
void AC97_CodecInit_MICIn(U16 AC97_fs)
{
AC97_Codec_Cmd(0,0x00,0x683F); //codec soft reset
AC97_Codec_Cmd(0,0x2A,0x0001); //variable rate enable
Uart_Printf("VRA Enable(1)/Disable(0): 0x%x\n",(0x1&AC97_Codec_Cmd(1,0x2A,0x0001)));
if(AC97_fs==48000){
//ADC Sampling frequency 48kHz
AC97_Codec_Cmd(0,0x32,0xbb80);
}
else if(AC97_fs==44100){
//ADC Sampling frequency 44.1kHz
AC97_Codec_Cmd(0,0x32,0xac44);
}
else if(AC97_fs==22050){
//ADC Sampling frequency 22.05kHz
AC97_Codec_Cmd(0,0x32,0x5622);
}
AC97_Codec_Cmd(0,0x26,(1<<9)); //all power on except DAC Block
Uart_Printf("\nAC97 Codec 0x26 Reg.: 0x%x\n\n", AC97_Codec_Cmd(1,0x26,0x0000));
AC97_Codec_Cmd(0,0x20,0x0000); //MIC1 Selected
AC97_Codec_Cmd(0,0x6e,0x0024); //ADC Input Slot => left slot6, right slot9, MIC GAIN VAL =1
AC97_Codec_Cmd(0,0x0e,0x0040); //BOOSTEN =1
AC97_Codec_Cmd(0,0x1a,0x0000); //Left, Right => MIC
AC97_Codec_Cmd(0,0x1c,0xff);
AC97_Codec_Cmd(0,0x78,0x0001); //ADC HPF Bypass
Input_Volume = AC97_Codec_Cmd(1,0x1c,0x0000); //Record Volume
}
U16 AC97_Codec_Cmd(U8 CMD_Read, U8 CMD_Offset, U16 CMD_Data)
{
U16 Codec_Stat;
if(CMD_Read == 0)
{
rAC_CODEC_CMD = (0<<23)|(CMD_Offset<<16)|(CMD_Data<<0);
Delay_After_CommandWrite(1); //30us delay.
}
else if (CMD_Read ==1)
{
rAC_CODEC_CMD = (1<<23)|(CMD_Offset<<16)|(CMD_Data<<0);
Delay(1000);
Codec_Stat = (U16)(rAC_CODEC_STAT & 0xFFFF);
Delay(1000);
return Codec_Stat;
}
else
return 0;
}
void PCM_In_Volume( U8 Up_Down_Volume)
{
if( ( Up_Down_Volume == 'u') | (Up_Down_Volume == 'U') )
{
if (Input_Volume == 0x0000)
{
Uart_Printf("Limit Volume Range!\n");
}
else
{
Input_Volume -= 0x0101;
AC97_Codec_Cmd(0,0x10, Input_Volume); // PCM In Volume Up
Uart_Printf("PCM In Volume Level : 0x%x\n", Input_Volume);
}
}
if ( ( Up_Down_Volume == 'd') | (Up_Down_Volume == 'D') )
{
if (Input_Volume == 0x1F1F)
{
Uart_Printf("Limit Volume Range!\n");
}
else
{
Input_Volume += 0x0101;
AC97_Codec_Cmd(0,0x10, Input_Volume); // PCM In Volume Down
Uart_Printf("PCM In Volume Level : 0x%4x\n", Input_Volume);
}
}
}
void PCM_Out_Volume(U8 Up_Down_Volume)
{
if( ( Up_Down_Volume == 'u') | (Up_Down_Volume == 'U') )
{
if (Output_Volume == 0x0000)
{
Uart_Printf("\nLimit Volume Range!");
}
else
{
Output_Volume -= 0x0101;
AC97_Codec_Cmd(0,0x04, Output_Volume); // PCM out Volume Up
Uart_Printf("\nHeadphone Volume Level (In AC97 Codec 04h Reg.): 0x%x", Output_Volume);
}
}
if ( ( Up_Down_Volume == 'd') | (Up_Down_Volume == 'D') )
{
if (Output_Volume == 0x1F1F)
{
Uart_Printf("\nLimit Volume Range!");
}
else
{
Output_Volume += 0x0101;
AC97_Codec_Cmd(0,0x04, Output_Volume); // PCM out Volume Down
Uart_Printf("\nHeadphone Volume Level (In AC97 Codec 04h Reg.): 0x%x", Output_Volume);
}
}
}
void Download_PCM_File(void)
{
pISR_UART1 = (unsigned)RxInt;
rINTMSK = ~( BIT_UART1);
rINTSUBMSK = ~(BIT_SUB_RXD1);
AC97_BUF = (U8 *)DOWN_BUF;
AC97_temp = AC97_BUF;
Uart_Printf("\nDownload the PCM(no ADPCM) file via Serial Port Transmit in DNW (With header & CS)!\n");
Uart_Printf("Max of PCM Size: 4M bytes\n");
while(((unsigned int)AC97_temp - (unsigned int)AC97_BUF) < 4)
{
Led_Display(0);
Delay(1500);
Led_Display(15);
Delay(1500);
}
AC97_size = *(AC97_BUF) | *(AC97_BUF + 1)<<8 | *(AC97_BUF + 2)<<16 | *(AC97_BUF + 3)<<24;
Uart_Printf("\nNow, Downloading... [ File Size : %7d( 0)]",AC97_size);
while(((unsigned int)AC97_temp - (unsigned int)AC97_BUF) < AC97_size)
Uart_Printf("\b\b\b\b\b\b\b\b%7d)",(unsigned int)AC97_temp - (unsigned int)AC97_BUF);
Uart_Printf("\b\b\b\b\b\b\b\b%7d)]\n",(unsigned int)AC97_temp - (unsigned int)AC97_BUF);
rINTSUBMSK |= BIT_SUB_RXD1;
AC97_size = *(AC97_BUF + 0x2c) | *(AC97_BUF + 0x2d)<<8 | *(AC97_BUF + 0x2e)<<16 | *(AC97_BUF + 0x2f)<<24;
AC97_size = (AC97_size>>1)<<1;
AC97_fs = *(AC97_BUF + 0x1c) | *(AC97_BUF + 0x1d)<<8 | *(AC97_BUF + 0x1e)<<16 | *(AC97_BUF + 0x1f)<<24;
Play_AC97_BUF = (U32 *)(AC97_BUF + 0x30); //DNW Header + PCM File Header => OffSet: 0x30
Uart_Printf("Sample PCM Data Size = %d\n", AC97_size);
Uart_Printf("Sampling Frequency = %d Hz\n", AC97_fs);
}
void AC97_PCMout_DMA1(U32 PCM_Size)
{
pISR_EINT0= (unsigned)Muting;
pISR_DMA1= (unsigned)DMA1_Play_Done;
rINTMSK = ~(BIT_DMA1|BIT_EINT0);
Play_AC97_BUF=(U32 *)(DOWN_BUF +0x30);
//DMA Ch1 for PCMInitialize
rDISRC1 = (int)Play_AC97_BUF;
rDISRCC1 = (0<<1) + (0<<0); //The source is in the system bus(AHB), Increment
rDIDST1 = ((U32)0x5b000018); //PCM Out Data Fifo
rDIDSTC1 = (1<<1) + (1<<0); //The destination is in the peripheral bus(APB), Fixed
rDCON1 = (1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(5<<24)+(1<<23)+(0<<22)+(2<<20)+(PCM_Size/4);
rDMASKTRIG1 = (0<<2) + (1<<1) + (0<<0); //No-stop[2], DMA1 channel On[1], No-sw trigger[0]
//AC97 Initialize
Uart_Printf("\nConnect Head Phone Line In to CON21 (Head Phone Out) on SMDK2440 and Press Key.\n");
Uart_Getch();
Uart_Printf("\nNow Play...\n");
Uart_Printf("To Volume Up, Press the 'u' key.\n");
Uart_Printf("To Volume Down, Press the 'd' key.\n");
Uart_Printf("To Mute On/Off, Press EINT0 Button.\n");
Uart_Printf("\nIf you want to exit, Press the 'x' key.\n");
Uart_Printf("Headphone Volume Register = 0x%x\n", Output_Volume);
//Transfer data enable using AC-Link
rAC_GLBCTRL = 0x200C;
//Uart_Printf("\nWrite Value to AC_GLBCTRL Reg. =>0x200C\n");
//Uart_Printf("Read Value from AC_GLBCTRL Reg. =>0x%x\n", rAC_GLBCTRL);
Delay(1000);
while(1)
{
//Uart_Printf("STAT3: 0x%x CURR_TC: 0x%x DCDST3: 0x%x\n", rDSTAT3&0x300000, rDSTAT3&0xfffff, rDCDST3);
Up_Down_Volume=Uart_Getch();
if( (Up_Down_Volume == 'x') | (Up_Down_Volume == 'X'))
break;
PCM_Out_Volume(Up_Down_Volume);
}
ClearPending(BIT_DMA1);
rDMASKTRIG1 = (1<<2); //DMA1 stop
rINTMSK|= (BIT_DMA1 | BIT_EINT0);
//AC97 PCM In Channel Finish
rAC_GLBCTRL &= ~(1<<13); //PCM Out Transfer Mode Off
Uart_Printf("\nEnd of Play!\n");
}
void AC97_PCMout_INT(U32 PCM_Size)
{
//Record AC97_BUF initialize
Rec_AC97_BUF = (U32 *)(DOWN_BUF);
Play_AC97_BUF = (Rec_AC97_BUF + 0x30);
End_AC97_BUF = (Rec_AC97_BUF + 0x30 + PCM_Size/4);
//IRQ Initialization
pISR_WDT_AC97= (unsigned)Irq_AC97_PCMout;
Uart_Printf("\nConnect Head Phone Line In to CON21 on SMDK2440 and Press any key.\n");
Uart_Getch();
Uart_Printf("\nNow Play...\n");
Uart_Printf("Headphone Volume Register = 0x%x\n", Output_Volume);
ClearPending(BIT_WDT_AC97);
rSUBSRCPND=(BIT_SUB_AC97);
rINTMSK=~(BIT_WDT_AC97);
rINTSUBMSK=~(BIT_SUB_AC97);
rAC_GLBCTRL = 0x4100C; //PCM Out channel threshold INT enable, PIO Mode On
while(1)
{
if(PCM_Out_INT_Exit == 1)
break;
}
rAC_GLBCTRL &= ~(1<<12); //PCM Out Transfer PIO Mode Off
rINTSUBMSK|=(BIT_SUB_WDT|BIT_SUB_AC97);
rINTMSK|=(BIT_WDT_AC97);
Uart_Printf("\nEnd of Play!\n");
}
void AC97_PCMin_DMA2(U32 PCM_Size)
{
Rec_AC97_BUF = (U32 *)(DOWN_BUF);
//IRQ Initialize
pISR_DMA2 = (unsigned)DMA2_Rec_Done;
rINTMSK = ~(BIT_DMA2);
//DMA2 Initialize
rDISRC2 = ((U32)0x5B000018); //PCM Input Data FIFO
rDISRCC2 = (1<<1) + (1<<0); //APB, Fix
rDIDST2 = (int)Rec_AC97_BUF; //Record AC97_BUF initializ
rDIDSTC2 = (0<<1) + (0<<0); //AHB, Increment
rDCON2 = (1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(5<<24)+(1<<23)+(1<<22)+(2<<20)+(PCM_Size/4);
Uart_Printf("Connect Sound Line Out to CON25(Line In) on SMDK2440\n");
Uart_Printf("Press any key to start record.\n");
Uart_Getch();
Uart_Printf("Recording...\n");
rDMASKTRIG2 = (0<<2) + (1<<1) + 0; //No-stop, DMA2 channel on, No-sw trigger
// Transfer data enable using AC-Link
rAC_GLBCTRL = 0x80C; // Transfer data enable using AC-Link
//Uart_Printf("\nWrite Value to AC_GLBCTRL Reg. =>0x80C\n");
//Uart_Printf("Read Value from AC_GLBCTRL Reg. =>0x%x\n", rAC_GLBCTRL);
while(AC97_Rec_Done ==0)
{
Uart_Printf(".");
Delay(3000);
//Uart_Printf("STAT2: 0x%x CURR_TC: 0x%x DCDST2: 0x%x\n", rDSTAT2&0x300000, rDSTAT2&0xfffff, rDCDST2);
}
AC97_Rec_Done = 0;
rDMASKTRIG2 = (1<<2); //DMA2 stop
rINTMSK |= BIT_DMA2;
//AC97 PCM In Channel Finish
rAC_GLBCTRL &= ~(1<<11); //PCM In Transfer Mode Off
Delay(1000);
Uart_Printf("\nEnd of Record!\n");
}
void AC97_PCMin_INT(U32 PCM_Size)
{
//Record AC97_BUF initialize
Rec_AC97_BUF = (U32 *)(DOWN_BUF);
Play_AC97_BUF = Rec_AC97_BUF + 0x30;
End_AC97_BUF = (Rec_AC97_BUF + 0x30 + PCM_Size/4);
//IRQ Initialization
pISR_WDT_AC97= (unsigned)Irq_AC97_PCMin;
Uart_Printf("Connect Sound Line Out to CON25(Line In) on SMDK2440\n");
Uart_Printf("Press any key to start record.\n");
Uart_Getch();
Uart_Printf("Recording...\n");
ClearPending(BIT_WDT_AC97);
rSUBSRCPND=(BIT_SUB_AC97);
rINTMSK=~(BIT_WDT_AC97);
rINTSUBMSK=~(BIT_SUB_AC97);
rAC_GLBCTRL = 0x2040C; //PCM In channel threshold INT enable, PIO Mode On
while(1)
{
if(PCM_In_INT_Exit == 1)
break;
}
rAC_GLBCTRL &= ~(1<<10); //PCM In Transfer PIO Mode Off
rINTSUBMSK|=(BIT_SUB_AC97);
rINTMSK|=(BIT_WDT_AC97);
Uart_Printf("\nEnd of Record!\n");
}
void AC97_MICin_DMA3(U32 MIC_Size)
{
Rec_AC97_BUF = (U32 *)(DOWN_BUF);
//IRQ Initialize
pISR_DMA3 = (unsigned)DMA3_Rec_Done;
rINTMSK=~(BIT_DMA3);
//DMA3 Initialize
rDISRC3 = ((U32)0x5B00001C); //MIC Input Data FIFO
rDISRCC3 = (1<<1) + (1<<0); //APB, Fix
rDIDST3 = (int)Rec_AC97_BUF; //Record AC97_BUF initializ
rDIDSTC3 = (0<<1) + (0<<0); //AHB, Increment
rDCON3 = (1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(5<<24)+(1<<23)+(1<<22)+(2<<20)+(MIC_Size/4);
Uart_Printf("Are you ready to record voice via MIC on SMDK2440?\n");
Uart_Printf("Press any key to start record.\n");
Uart_Getch();
Uart_Printf("Recording...\n");
rDMASKTRIG3 = (0<<2) + (1<<1) + 0; //No-stop, DMA3 channel on, No-sw trigger
// Transfer data enable using AC-Link
rAC_GLBCTRL = 0x20C; // Transfer data enable using AC-Link
while(AC97_Rec_Done ==0)
{
Uart_Printf(".");
Delay(3000);
//Uart_Printf("STAT3: 0x%x CURR_TC: 0x%x DCDST3: 0x%x\n", rDSTAT3&0x300000, rDSTAT3&0xfffff, rDCDST3);
}
AC97_Rec_Done = 0;
rDMASKTRIG3 = (1<<2); //DMA3 stop
rINTMSK |= BIT_DMA3;
//AC97 MIC In Channel Finish
rAC_GLBCTRL &= ~(1<<9); //MIC In Transfer Mode Off
Uart_Printf("\nEnd of Record!\n");
}
void AC97_MICin_INT(U32 PCM_Size)
{
//Record AC97_BUF initialize
Rec_AC97_BUF = (U32 *)(DOWN_BUF);
Play_AC97_BUF = Rec_AC97_BUF + 0x30;
End_AC97_BUF = (Rec_AC97_BUF + 0x30 + PCM_Size/4);
//IRQ Initialization
pISR_WDT_AC97= (unsigned)Irq_AC97_MICin;
Uart_Printf("Are you ready to record voice via MIC on SMDK2440?\n");
Uart_Printf("Press any key to start record.\n");
Uart_Getch();
Uart_Printf("Recording...\n");
ClearPending(BIT_WDT_AC97);
rSUBSRCPND=(BIT_SUB_AC97);
rINTMSK=~(BIT_WDT_AC97);
rINTSUBMSK=~(BIT_SUB_AC97);
rAC_GLBCTRL = 0x1010C; //MIC In channel threshold INT enable, PIO Mode On
while(1)
{
if(PCM_In_INT_Exit == 1)
break;
}
rAC_GLBCTRL &= ~(1<<8); //MIC In Transfer PIO Mode Off
rINTSUBMSK|=(BIT_SUB_AC97);
rINTMSK|=(BIT_WDT_AC97);
Uart_Printf("\nEnd of Record!\n");
}
void AC97_CodecExit_PCMOut(void)
{
//DACs off
Uart_Printf("\n\n=>DACs off PR1\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Analog off
Uart_Printf("\n=>Analog off PR2\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Digital I/F off
Uart_Printf("\n=>Digital I/F off PR4\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
void AC97_CodecExit_PCMIn(U16 DACs_off)
{
//ADCs off
Uart_Printf("\n\n=>ADCs off PR0\n");
AC97_Codec_Cmd(0,0x26,(1<<8));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
if(DACs_off == 1)
{
//DACs off
Uart_Printf("\n\n=>DACs off PR1\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
//Analog off
Uart_Printf("\n=>Analog off PR2\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Digital I/F off
Uart_Printf("\n=>Digital I/F off PR4\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
void AC97_CodecExit_MICIn(U16 DACs_off)
{
//ADCs off
Uart_Printf("\n\n=>ADCs off PR0\n");
AC97_Codec_Cmd(0,0x26,(1<<8));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
if(DACs_off == 1)
{
//DACs off
Uart_Printf("\n\n=>DACs off PR1\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
//Analog off
Uart_Printf("\n=>Analog off PR2\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
//Digital I/F off
Uart_Printf("\n=>Digital I/F off PR4\n");
AC97_Codec_Cmd(0,0x26,(1<<8)|(1<<9)|(1<<10)|(1<<12));
AC97_Controller_State();
Uart_Printf("AC97 Codec Powerdown Ctrl/Stat 0x26 Reg.: 0x%x\n", AC97_Codec_Cmd(1,0x26,0x0000));
}
U16 AC97_Select_SamplingRate(void)
{
int i;
Uart_Printf("\nSelect ADC/DAC Rate\n");
Uart_Printf("0:22.05kHz, 1:44.1kHz, 2:48kHz\n");
i = Uart_GetIntNum();
switch(i)
{
case 0:
return 22050;
break;
case 1:
return 44100;
break;
case 2:
return 48000;
break;
default:
return 48000;
break;
}
}
void AC97_Controller_State(void)
{
U8 state;
state=(U8)(rAC_GLBSTAT);
switch(state)
{
case 0:
Uart_Printf("AC97 Controller State: Idle\n");
break;
case 1:
Uart_Printf("AC97 Controller State: Init\n");
break;
case 2:
Uart_Printf("AC97 Controller State: Ready\n");
break;
case 3:
Uart_Printf("AC97 Controller State: Active\n");
break;
case 4:
Uart_Printf("AC97 Controller State: LP\n");
break;
case 5:
Uart_Printf("AC97 Controller State: Warm\n");
break;
default:
break;
}
}
void Delay_After_CommandWrite(int time)
{
// time=0: adjust the Delay function by WatchDog timer.
// time>0: the number of loop time
// Delay time resolution has 30us.
int i, adjust=0;
if(time==0)
{
time = 300;
adjust = 1;
delayLoopCount = 500;
//PCLK/1M,Watch-dog disable,1/64,interrupt disable,reset disable
rWTCON = ((PCLK/1000000-1)<<8)|(2<<3);
rWTDAT = 0xffff; //for first update
rWTCNT = 0xffff; //resolution=64us @any PCLK
rWTCON = ((PCLK/1000000-1)<<8)|(2<<3)|(1<<5); //Watch-dog timer start
}
for(;time>0;time--)
for(i=0;i 64us, 300*500 cycle runtime = 64*i us
delayLoopCount = 4500000/(i*64); //300*500:64*i=1*x:30 -> x=150000*30/(64*i)
}
}
void Delay_Init(void)
{
Delay(0); //Delay Time Resolution => 100us Adjust
Delay_After_CommandWrite(0); //Delay Time Resolution => 30us Adjust
}
/* ISRs */
void __irq AC97_Codec_Ready(void)
{
Delay_Init();
if ( (rAC_GLBSTAT& 0x400000))
{
Codec_Ready_Irq=1;
Uart_Printf("Codec Ready!\n");
rAC_GLBCTRL &= ~(0x400000); // codec ready interrupt disable
}
rSUBSRCPND=(BIT_SUB_AC97);
ClearPending(BIT_WDT_AC97);
rINTSUBMSK &= ~(BIT_SUB_AC97);
rINTMSK &=~(BIT_WDT_AC97);
}
void __irq DMA1_Play_Done(void)
{
ClearPending(BIT_DMA1);
Uart_Printf("\n~~~");
}
void __irq DMA2_Rec_Done(void)
{
ClearPending(BIT_DMA2);
AC97_Rec_Done = 1;
}
void __irq DMA3_Rec_Done(void)
{
ClearPending(BIT_DMA3);
AC97_Rec_Done = 1;
}
void __irq Irq_AC97_PCMout(void)
{
U32 i, AC97_Stat;
rINTMSK |=(BIT_WDT_AC97);
rINTSUBMSK|=(BIT_SUB_AC97);
AC97_Stat = rAC_GLBSTAT;
if (AC97_Stat & AC97_PCM_OUT_THRESHOLD)
{
for(i=0; i