📄 pcm.c
字号:
I2SCODEC_WrSerial(0x34, 0x2d, 0x80); //Power Management(3) <<Power up L/ROUT1 outputs >>
IIC_close();
return 1;
#endif
}
bool PCM_CodecInitPCMInOut(unsigned int eSync, unsigned char eMSBPos, unsigned int eSclk, unsigned char eClkSrc)
{
//play & record
IIC_open( (unsigned int)200000); // Serial EEPROM IIC clk = 200KHz
// address<<1 | data>>8, data[7:0]
I2SCODEC_WrSerial(0x34, 0x3e, 0x00); //Reset
I2SCODEC_WrSerial(0x34, 0x28, 0xd0); //PWR Management(1) << Power up VMID[50Kohm]; VREF; VDAC >>
I2SCODEC_WrSerial(0x34, 0x2e, 0x03); //PWR Management(4) << Power up L/RMIX >>
Delay(1000);
I2SCODEC_WrSerial(0x34, 0x02, 0x08); //DAC Control Mute
I2SCODEC_WrSerial(0x34, 0x04, 0x00); //ADC Control
if (eSync == DURING_PCMSYNC_HIGH)
I2SCODEC_WrSerial(0x34, 0x07, 0xb3); //PCM Audio I/F Mode B
else
I2SCODEC_WrSerial(0x34, 0x07, 0xa3); //PCM Audio I/F Mode A
I2SCODEC_WrSerial(0x34, 0x08, 0x0a); //HiFi Audio I/F
I2SCODEC_WrSerial(0x34, 0x0a, 0x33); //Interface Control << Voice Codec >>
if (eSync == SYNC_8K)
I2SCODEC_WrSerial(0x34, 0x0c, 0x0c); //Sync Rate Control 8KHz
else if (eSync == SYNC_16K)
I2SCODEC_WrSerial(0x34, 0x0c, 0x14); //Sync Rate Control 16KHz
else if (eSync == SYNC_32K)
I2SCODEC_WrSerial(0x34, 0x0c, 0x18); //Sync Rate Control 32KHz
else if (eSync == SYNC_48K)
I2SCODEC_WrSerial(0x34, 0x0c, 0x00); //Sync Rate Control 48KHz
else if (eSync == SYNC_96K)
I2SCODEC_WrSerial(0x34, 0x0c, 0x1e); //Sync Rate Control 96KHz
I2SCODEC_WrSerial(0x34, 0x0e, 0x97); //Sample Rate Control (2), Don't care in case of slave mode
I2SCODEC_WrSerial(0x34, 0x10, 0xff); //Left DAC Volume
I2SCODEC_WrSerial(0x34, 0x12, 0xff); //Right DAC Volume
I2SCODEC_WrSerial(0x34, 0x14, 0x0f); //Bass Control
I2SCODEC_WrSerial(0x34, 0x16, 0x0f); //Treble Control
I2SCODEC_WrSerial(0x34, 0x18, 0x7b); //ALC 1
I2SCODEC_WrSerial(0x34, 0x1a, 0x00); //ALC 2
I2SCODEC_WrSerial(0x34, 0x1c, 0x32); //ALC 3
I2SCODEC_WrSerial(0x34, 0x1e, 0x00); //Noise Gate
I2SCODEC_WrSerial(0x34, 0x21, 0xc3); //Left ADC Volume
I2SCODEC_WrSerial(0x34, 0x23, 0xc3); //Right ADC Volume
I2SCODEC_WrSerial(0x34, 0x24, 0xc0); //Additional Control
I2SCODEC_WrSerial(0x34, 0x26, 0x00); //Three D Control
I2SCODEC_WrSerial(0x34, 0x28, 0xc0); //Power Management(1) << Power up VMID[50K ohm]; VREF >>
I2SCODEC_WrSerial(0x34, 0x2a, 0x0c); //Power Management(2) << Power up ADCL/R >>
I2SCODEC_WrSerial(0x34, 0x2c, 0x00); //Power Management(3)
I2SCODEC_WrSerial(0x34, 0x2e, 0x00); //Power Management(4)
I2SCODEC_WrSerial(0x34, 0x30, 0x00); //ID Register
I2SCODEC_WrSerial(0x34, 0x32, 0x00); //Int. Polarty
I2SCODEC_WrSerial(0x34, 0x34, 0x00); //Int. Enable
I2SCODEC_WrSerial(0x34, 0x36, 0x00); //GPIO Control (1)
I2SCODEC_WrSerial(0x34, 0x38, 0x00); //GPIO Control (2)
I2SCODEC_WrSerial(0x34, 0x40, 0x55); //Record Mix (1)
I2SCODEC_WrSerial(0x34, 0x42, 0x05); //Record Mix (2)
I2SCODEC_WrSerial(0x34, 0x44, 0x50); //Left Out Mix(1)
I2SCODEC_WrSerial(0x34, 0x47, 0x55); //Left Out Mix(2) << Set the VXD2LO bit (Voice DAC to Left Output >>
I2SCODEC_WrSerial(0x34, 0x48, 0x50); //Rigth Out Mix(1)
I2SCODEC_WrSerial(0x34, 0x4b, 0x55); //Right Out Mix(2) << Set the VXD2RO bit (Voice DAC to Right Output) >>
I2SCODEC_WrSerial(0x34, 0x4c, 0x50); //Mono Out Mix(1)
I2SCODEC_WrSerial(0x34, 0x4e, 0x55); //Mono Out Mix(2)
I2SCODEC_WrSerial(0x34, 0x51, 0x79); //LOUT1 Volume << Set Left OUtput 1 Volume Update bit to '1' & Volume Level to Default >>
I2SCODEC_WrSerial(0x34, 0x53, 0x79); //ROUT1 Volume << Set Right OUtput 1 Volume Update bit to '1' & Volume Level to Default >>
I2SCODEC_WrSerial(0x34, 0x54, 0x79); //LOUT2 Volume
I2SCODEC_WrSerial(0x34, 0x56, 0x79); //ROUT2 Volume
I2SCODEC_WrSerial(0x34, 0x58, 0x79); //MONO Out
I2SCODEC_WrSerial(0x34, 0x5a, 0x00); //Output Control
I2SCODEC_WrSerial(0x34, 0x5c, 0x05); //ADC Input Mode << Set L/R ADC input select to Line 1/2 '01' >>
I2SCODEC_WrSerial(0x34, 0x5e, 0x00); //Input Control (1)
I2SCODEC_WrSerial(0x34, 0x60, 0x00); //Input Control (2)
I2SCODEC_WrSerial(0x34, 0x62, 0x97); //Left Input Volume
I2SCODEC_WrSerial(0x34, 0x64, 0x97); //Right Input Volume
I2SCODEC_WrSerial(0x34, 0x66, 0x00); //MIC Bias Comp Control
I2SCODEC_WrSerial(0x34, 0x68, 0x04); //Clock Control << Clock for Voice Codec = MCLK or PLL1
I2SCODEC_WrSerial(0x34, 0x6a, 0x00); //PLL1 Control (1)
I2SCODEC_WrSerial(0x34, 0x6c, 0x83); //PLL1 Control (2)
I2SCODEC_WrSerial(0x34, 0x6e, 0x24); //PLL1 Control (3)
I2SCODEC_WrSerial(0x34, 0x71, 0xba); //PLL1 Control (4)
I2SCODEC_WrSerial(0x34, 0x72, 0x00); //PLL2 Control (1)
I2SCODEC_WrSerial(0x34, 0x74, 0x83); //PLL2 Control (2)
I2SCODEC_WrSerial(0x34, 0x76, 0x24); //PLL2 Control (3)
I2SCODEC_WrSerial(0x34, 0x79, 0xba); //PLL2 Control (4)
I2SCODEC_WrSerial(0x34, 0x7a, 0x00); //Bias Control
I2SCODEC_WrSerial(0x34, 0x7e, 0x00); //Additional Control
I2SCODEC_WrSerial(0x34, 0x2d, 0x80); //Power Management(3) <<Power up L/ROUT1 outputs >>
IIC_close();
}
void PCM_CodecExitPCMOut(void)
{
#if ( PCM_CODEC_NAME == AK2430)
I2SCODEC_WrSerial(0x9e, 0x04, 0x01); //EPL/R Amp Off
Delay(1300);
I2SCODEC_WrSerial(0x9e, 0x07, 0x00); //sw_COL Close and other sw Open
I2SCODEC_WrSerial(0x9e, 0x08, 0x00); //sw_COR Close and othr sw Open
I2SCODEC_WrSerial(0x9e, 0x09, 0x00); //sw_EPL, sw_EPR Amp output
I2SCODEC_WrSerial(0x9e, 0x04, 0x00); //RXSUM Off
I2SCODEC_WrSerial(0x9e, 0x05, 0x00); //PCM Codec Off
#elif ( PCM_CODEC_NAME == WM9713)
AC97_Codec_Cmd(0,0x3E, 0xffff); //Disable HPL/R output PGA's
AC97_Codec_Cmd(0,0x26, 0xff00); //Disable I/P PGA's nad Mixers
Delay(1300);//added for continuous test
#endif
}
void PCM_pcmtest1()
{
int irqstatold, irqstatnew;
printf("start tx dma disable test \n");
rPCM_CTL1&= ~PCM_PCM_ENABLE;
rPCM_CTL1&= ~PCM_TX_DMA_EN;
irqstatold=rPCM_IRQ_STAT1;
do
{
printf("tx fifo read for t32 test %x\n", rPCM_TXFIFO1);
irqstatnew=rPCM_IRQ_STAT1;
if(irqstatnew!=irqstatold)
{
printf("IRQ STAT : 0x%x, FIFO STAT : 0x%x\n", irqstatnew, rPCM_FIFO_STAT1);
}
irqstatold = irqstatnew;
}while (irqstatnew != 0xc80);
}
void PCM_pcmtest2()
{
int irqstatold, irqstatnew;
printf("start tx dma disable test \n");
rPCM_CTL1&= ~PCM_PCM_ENABLE;
rPCM_CTL1&= ~PCM_TX_DMA_EN;
irqstatold=rPCM_FIFO_STAT1;
do
{
printf("tx fifo read for t32 test %x\n", rPCM_TXFIFO1);
irqstatnew=rPCM_FIFO_STAT1 ;
if(irqstatnew!=irqstatold)
{
printf("IRQ STAT : 0x%x, FIFO STAT : 0x%x fifo cnt : %d\n", rPCM_IRQ_STAT1, irqstatnew, irqstatnew>>14);
}
irqstatold = irqstatnew;
}while (irqstatnew != 0x3000);
}
void PCM_fifostat()
{
int fifostat=(g_oPCMState.PCMPort==0)?rPCM_FIFO_STAT0:rPCM_FIFO_STAT1;
int irqstat=(g_oPCMState.PCMPort==0)?rPCM_IRQ_STAT0:rPCM_IRQ_STAT1;
int irqctrl=(g_oPCMState.PCMPort==0)?rPCM_IRQ_CTL0:rPCM_IRQ_CTL1;
printf("FIFO STAT : 0x%x tx_fifo_cnt : %d rx_fifo_cnt : %d %s%s%s%s %s%s%s%s \n", fifostat, fifostat>>14, (fifostat>>4)&0x3f,
(fifostat & FIFO_TXFIFO_EMPTY )?"TX empty ":"",
(fifostat & FIFO_TXFIFO_ALMOST_EMPTY )?"TX almost empty ":"",
(fifostat & FIFO_TXFIFO_FULL )?"TX full ":"",
(fifostat & FIFO_TXFIFO_ALMOST_FULL )?"TX almost full ":"",
(fifostat & FIFO_RXFIFO_EMPTY )?"RX empty ":"",
(fifostat & FIFO_RXFIFO_ALMOST_EMPTY )?"RX almost empty ":"",
(fifostat & FIFO_RXFIFO_FULL )?"RX full ":"",
(fifostat & FIFO_RXFIFO_ALMOST_FULL )?"RX almost full ":""
);
printf("IRQ STAT : 0x%x %s%s %s%s%s%s%s%s %s%s%s%s%s%s\n", irqstat,
(irqstat & IRQ_PENDING )?"irq pending ":"",
(irqstat & TRANSFER_DONE )?"transfer done ":"",
(irqstat & TXFIFO_EMPTY )?"TX empty ":"",
(irqstat & TXFIFO_ALMOST_EMPTY )?"TX almost empty ":"",
(irqstat & TXFIFO_FULL )?"TX full ":"",
(irqstat & TXFIFO_ALMOST_FULL )?"TX almost full ":"",
(irqstat & TXFIFO_ERROR_STARVE )?"TX starve ":"",
(irqstat & TXFIFO_ERROR_OVERFLOW)?"TX overflow ":"",
(irqstat & RXFIFO_EMPTY )?"RX empty ":"",
(irqstat & RXFIFO_ALMOST_EMPTY )?"RX almost empty ":"",
(irqstat & RXFIFO_FULL )?"RX full ":"",
(irqstat & RXFIFO_ALMOST_FULL )?"RX almost full ":"",
(irqstat & RXFIFO_ERROR_STARVE )?"RX starve ":"",
(irqstat & RXFIFO_ERROR_OVERFLOW)?"RX overflow ":""
);
printf("IRQ CTRL : 0x%x %s%s %s%s%s%s%s%s %s%s%s%s%s%s\n", irqctrl,
(irqctrl & EN_IRQ_TO_ARM )?"en irq to arm ":"",
(irqctrl & TRANSFER_DONE )?"transfer done ":"",
(irqctrl & TXFIFO_EMPTY )?"TX empty ":"",
(irqctrl & TXFIFO_ALMOST_EMPTY )?"TX almost empty ":"",
(irqctrl & TXFIFO_FULL )?"TX full ":"",
(irqctrl & TXFIFO_ALMOST_FULL )?"TX almost full ":"",
(irqctrl & TXFIFO_ERROR_STARVE )?"TX starve ":"",
(irqctrl & TXFIFO_ERROR_OVERFLOW)?"TX overflow ":"",
(irqctrl & RXFIFO_EMPTY )?"RX empty ":"",
(irqctrl & RXFIFO_ALMOST_EMPTY )?"RX almost empty ":"",
(irqctrl & RXFIFO_FULL )?"RX full ":"",
(irqctrl & RXFIFO_ALMOST_FULL )?"RX almost full ":"",
(irqctrl & RXFIFO_ERROR_STARVE )?"RX starve ":"",
(irqctrl & RXFIFO_ERROR_OVERFLOW)?"RX overflow ":""
);
}
void PCM_PCMSetting()
{
bool bret;
unsigned int uSclkDiv, uSyncDiv, uSclkSel;
unsigned int uTxMsbPos, uRxMsbPos;
bret=PCM_GetClkValAndClkDir(&uSclkDiv, &uSyncDiv);
if(!bret)
{
printf("clock can not be made, exit");
return;
}
if(g_oPCMState.PCMClkSrc == PCM_PCLK) uSclkSel = 1<<18;
else uSclkSel = 0<<18;
printf("uSclkDiv: 0x%x\n", uSclkDiv);
printf("uSyncDiv: 0x%x\n", uSyncDiv);
{
double cdclk;
double sclk;
double syncclk;
cdclk = (g_oPCMState.PCMClkSrc == PCM_PCLK) ? (double)PCLK : (double)g_oPCMState.EXTCDCLKFreq;
sclk = cdclk/(2*( uSclkDiv+ 1) );
syncclk = sclk /( uSyncDiv+ 1 );
printf("Actural value\n\
Source_Clk : %f PCM_SCLK : %fKHz PCM_Syncclk: %fKHz\n",
cdclk, sclk, syncclk);
}
if(g_oPCMState.PCMMSBPosition == AFTER_PCMSYNC_HIGH)//min 17fs is needed for recording
{
uTxMsbPos = TX_MSB_POS1;
uRxMsbPos = RX_MSB_POS1;
}
else if(g_oPCMState.PCMMSBPosition == DURING_PCMSYNC_HIGH)//min 16fs is needed
{
uTxMsbPos = TX_MSB_POS0;
uRxMsbPos = RX_MSB_POS0 ;
}
//PCM Clock Setting & Transfer data setting
if(g_oPCMState.PCMPort == PCM_PORT0)
{
rPCM_CLKCTL0 = ( uSclkSel | (uSclkDiv<<9) | (uSyncDiv<<0) );
rPCM_CTL0 = ( uTxMsbPos |uRxMsbPos);//pcm_txfifo_disable
}
else
{
rPCM_CLKCTL1 = ( uSclkSel | (uSclkDiv<<9) | (uSyncDiv<<0) );
rPCM_CTL1 = ( uTxMsbPos |uRxMsbPos);//pcm_txfifo_disable
}
}
void PCM_TXFIFOwaitTillFULL()
{
if(g_oPCMState.PCMPort == PCM_PORT0)
{
while( FIFO_TXFIFO_COUNT0<16) ;
}
else
{
while( FIFO_TXFIFO_COUNT1<16) ;
}
}
void PCM_TXFIFOwaitTillEmpty()
{
if(g_oPCMState.PCMPort == PCM_PORT0)
{
while( FIFO_TXFIFO_COUNT0!=0) ;
}
else
{
while( FIFO_TXFIFO_COUNT1!=0) ;
}
}
void PCM_PCMInDMASetting(unsigned int uRecBufferAddr, unsigned int uPcmSize)
{
unsigned char Burst, Datasize;
unsigned char rBurst, rDatasize;
unsigned int estInitialTC;//
unsigned int realInitialTC;
Burst = 1;//1: single, 4 : 4burst - doesn't work?
Datasize = 4;//1:byte, 2:half word 4:word [transfer unit]
rBurst = (Burst == 1)? 0 : 1;//0:single, 1:4 burst
rDatasize = (Datasize==1)?0:
(Datasize==2)?1:2;//0:byte, 1:half word, 2: word.
estInitialTC = uPcmSize/ ( Burst*Datasize );// playsize(byte) / ( single or burst * transfer unit ) = tc
if(estInitialTC > 0xfffff )//2^20 = 1M
{
realInitialTC = 0xfffff;
printf("size of data to record are larger than DMA count max, it adjusted from %d to %d\n\
or you can use dma autoreload function\n", estInitialTC, realInitialTC);
}
else
realInitialTC = estInitialTC;
//DMA Setting
rDISRC2 = (g_oPCMState.PCMPort == PCM_PORT0)? ((unsigned int)0x5c00000c) : ((unsigned int)0x5c00010c);//PCM Input Data FIFO
rDISRCC2 = (1<<1) + (1<<0); //APB, Fix
rDIDST2 = uRecBufferAddr; //Record PCM buff loc
rDIDSTC2 = (0<<1) + (0<<0); //AHB, Increment
// 31: demand 30: sync pclk 29:curr_tc int setting 28:unit transfer 27:single service 22: auto reload off 20: half word
rDCON2 = (U32)(0<<31)+(0<<30)+(1<<29)+(rBurst<<28)+(0<<27)+(1<<22)+(rDatasize<<20)+realInitialTC;
rDMAREQSEL2 = (g_oPCMState.PCMPort == PCM_PORT0)? ( (13<<1) + (1<<0) ) : ( (15<<1) + (1<<0) );
}
void PCM_PCMOutDMASetting(unsigned int uPlayBufferAddr, unsigned int uPcmSize)
{
unsigned char Burst, Datasize;
unsigned char rBurst, rDatasize;
unsigned int estInitialTC;//
unsigned int realInitialTC;
Burst = 1;//1: single, 4 : 4burst - doesn't work?
Datasize = 4;//1:byte, 2:half word 4:word [transfer unit]
rBurst = (Burst == 1)? 0 : 1;//0:single, 1:4 burst
rDatasize = (Datasize==1)?0:
(Datasize==2)?1:2;//0:byte, 1:half word, 2: word.
estInitialTC = uPcmSize/ ( Burst*Datasize );// playsize(byte) / ( single or burst * transfer unit ) = tc
if(estInitialTC > 0xfffff )//2^20 = 1M
{
realInitialTC = 0xfffff;
printf("size of data to record are larger than DMA count max, it adjusted from %d to %d\n\
or you can use dma autoreload function\n", estInitialTC, realInitialTC);
}
else
realInitialTC = estInitialTC;
//DMA Setting
rDISRC1 = uPlayBufferAddr;
rDISRCC1 = (0<<1) + (0<<0); //The source is in the system bus(AHB), Increment
rDIDST1 = (g_oPCMState.PCMPort == PCM_PORT0)? ((unsigned int)0x5c000008) : ((unsigned int)0x5c000108);//PCM Out Data Fifo
rDIDSTC1 = (0<<2)+ (1<<1) + (1<<0); //int will occur when tc reaches 0, The destination is in the peripheral bus(APB), Fixed
// 31: demand 30: sync pclk 29:curr_tc 0 intterupt on 28:unit transfer 27:single service 22: auto reload off 20: half word
rDCON1 = (U32)(0<<31)+(0<<30)+(1<<29)+(rBurst<<28)+(0<<27)+(1<<22)+(rDatasize<<20)+realInitialTC;//[28] 0 unit, [20] 2'b10 word. [19:0]count
rDMAREQSEL1 = (g_oPCMState.PCMPort == PCM_PORT0)? ( (12<<1) + (1<<0) ) : ( (14<<1) + (1<<0) );
}
//pcmsize(byte) 16bit mono continous format
bool PCM_PCMInDMA(unsigned int uRecBufferAddr, unsigned int uPcmSize, bool (*fn_extra)(void))
{
unsigned char uChar;
unsigned int *rPCM_CTL=(g_oPCMState.PCMPort==0)?(unsigned int *)&rPCM_CTL0:(unsigned int *)&rPCM_CTL1;
unsigned int *rPCM_CLKCTL=(g_oPCMState.PCMPort==0)?(unsigned int *)&rPCM_CLKCTL0:(unsigned int *)&rPCM_CLKCTL1;
int cnt=0;
bool bret = TRUE;
//IRQ Initialization
g_interrupt_cnt=0;
if(g_oPCMState.PCMPort == PCM_PORT0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -