📄 audiodrv.c
字号:
#include "def.h"
#include "2440addr.h"
#include "2440lib.h"
#include "AudioDrv.h"
#include "dma.h"
#define AUDIO_PLAY_DEV 0x100
#define AUDIO_REC_DEV 0x101
#define DEVICE_REC 2
#define DEVICE_PLAY 1
#define DEVICE_FREE 0
#define PLAY 0
#define RECORD 1
#define PLAY_DMA_ATTR ((AUDIO_PLAY_DEV<<16)|SRC_LOC_AHB|SRC_ADDR_INC|DST_LOC_APB|DST_ADDR_FIXED|REQ_IISDO)
#define PLAY_DMA_MODE (HANDSHAKE_MODE|SYNC_APB|DONE_GEN_INT|TSZ_UNIT|SINGLE_SVC|HW_TRIG|RELOAD_OFF|DSZ_16b)
#define REC_DMA_ATTR ((AUDIO_REC_DEV<<16)|SRC_LOC_APB|SRC_ADDR_FIXED|DST_LOC_AHB|DST_ADDR_INC|REQ_IISDI)
#define REC_DMA_MODE (HANDSHAKE_MODE|SYNC_APB|DONE_GEN_INT|TSZ_UNIT|SINGLE_SVC|HW_TRIG|RELOAD_OFF|DSZ_16b)
static void IIS_PortSetting( void );
static void _WrL3Addr( U8 data );
static void _WrL3Data( U8 data , int halt );
static void Init1341( char mode );
static void AdjVolume( U16 volume );
static void PlayPause( U8 mode );
//static void Muting(void);
static void StartPlay( void );
static void __irq PlayDMA2Done( void );
static LPWAVEHDR lpPlayFstBlk, lpRecFstBlk;
static LPWAVEHDR lpPlayLstBlk, lpRecLstBlk;
static LPWAVEHDR lpPlayCurBlk, lpRecCurBlk;
static U32 PlayTotBlks, RecTotBlks;
static U32 save_MPLLCON;
static struct
{
U16 Freq;
U32 MPLL;
U16 PreScaler;
U8 ofs;
}CodecPara[7] =
{
{8000,( 123 << 12 ) | ( 6 << 4 ) | 0,( 23 << 5 ) | 23,0}, {11025,( 229 << 12 ) | ( 5 << 4 ) | 1,( 11 << 5 ) | 11,1},
{16000,( 123 << 12 ) | ( 6 << 4 ) | 0,( 11 << 5 ) | 11,0},
{22050,( 229 << 12 ) | ( 5 << 4 ) | 1,( 5 << 5 ) | 5,1},
//{22050,(0x96<<12)|(5<<4)|1,(5<<5)|5,0},
{32000,( 123 << 12 ) | ( 6 << 4 ) | 0,( 5 << 5 ) | 5,0}, {44100,( 229 << 12 ) | ( 5 << 4 ) | 1,( 2 << 5 ) | 2,1},
{48000,( 123 << 12 ) | ( 6 << 4 ) | 0,( 3 << 5 ) | 3,0}
};
static struct
{
HWAVEOUT handle;
U16 wFormatTag;
U16 nChannels;
U16 wBitsPerSample;
CallBackProc CallBack;
U32 CallBackInst;
U8 FsIdx;
U32 DevReq;
U8 Status;
}PlayStatus, RecStatus;
static U16 PlayVolume = 0xffff;
//static U8 inner_buf[32*1024];
void DbgChgUartDiv( void )
{
Uart_Init( 0 , 115200 );
}
static void SetSysFclk( U32 MPLL )
{
U32 mdiv, pdiv, sdiv, val;
U32 mclk;
mdiv = ( MPLL >> 12 ) & 0xff;
pdiv = ( MPLL >> 4 ) & 0xff;
sdiv = MPLL & 0xf;
val = 1;
while ( sdiv-- )
{
val *= 2;
}
mclk = ( ( mdiv + 8 ) * 12000000 ) / ( ( pdiv + 2 ) * val ) ;
Uart_Init( mclk >> 2 , 115200 ) ;
}
/************************* Play Function ***********************/
MMRESULT waveOutOpen( LPHWAVEOUT phwo , UINT uDeviceID , LPWAVEFORMATEX pwfx , DWORD dwCallback ,
DWORD dwCallbackInstance , DWORD fdwOpen )
{
U8 i;
U8 err = 0;
if ( pwfx->wFormatTag != WAVE_FORMAT_PCM ) //only support PCM
err = 1;
if ( pwfx->nChannels != 2 ) //must be stero
err = 1;
if ( pwfx->wBitsPerSample % 8 ) //8 or 16 bits
err = 1;
for ( i = 0; i < 7; i++ )
if ( pwfx->nSamplesPerSec == CodecPara[i].Freq )
break;
if ( i == 7 )
err = 1;
if ( ( pwfx->nChannels * pwfx->wBitsPerSample ) / 8 != pwfx->nBlockAlign )
err = 1;
if ( pwfx->nAvgBytesPerSec != pwfx->nSamplesPerSec * pwfx->nBlockAlign )
err = 1;
if ( err )
return WAVERR_BADFORMAT; //check format parameters
if ( PlayStatus.Status != DEVICE_FREE )
return MMSYSERR_BADDEVICEID;
PlayStatus.DevReq = RequestDMA( PLAY_DMA_ATTR , PLAY_DMA_MODE );
if ( PlayStatus.DevReq == REQUEST_DMA_FAIL )
return MMSYSERR_BADDEVICEID;
PlayStatus.handle = *phwo;
PlayStatus.wFormatTag = pwfx->wFormatTag;
PlayStatus.nChannels = pwfx->nChannels;
PlayStatus.wBitsPerSample = pwfx->wBitsPerSample;
PlayStatus.FsIdx = i;
PlayStatus.CallBack = ( CallBackProc ) dwCallback;
PlayStatus.CallBackInst = dwCallbackInstance;
PlayStatus.Status = DEVICE_PLAY;
save_MPLLCON = rMPLLCON; //save MPLLCON value
//rMPLLCON = CodecPara[PlayStatus.FsIdx].MPLL;
SetSysFclk( CodecPara[PlayStatus.FsIdx].MPLL );
rCLKCON |= 0x20000; //enable IIS clock
DbgChgUartDiv();
// ChangeClockDivider(1,1); //1:2:4
// ChangeMPllValue(0x96,0x5,0x1); //FCLK=135.428571MHz (PCLK=33.857142MHz)
// Uart_Init(33857142,115200);
IIS_PortSetting();
pISR_DMA2 = ( U32 ) PlayDMA2Done;
EnableIrq( BIT_DMA2 );
PlayTotBlks = 0;
Init1341( PLAY );
waveOutSetVolume( PlayStatus.handle , PlayVolume );
return MMSYSERR_NOERROR;
}
MMRESULT waveOutClose( HWAVEOUT hwo )
{
if ( ( PlayStatus.handle != hwo ) || ( PlayStatus.Status != DEVICE_PLAY ) )
return MMSYSERR_INVALHANDLE;
rIISCON = 0x0; //IIS Interface stop
rIISFCON = 0x0; //For FIFO flush
rCLKCON &= ~0x20000; //disable IIS colock
//rMPLLCON = save_MPLLCON; //restore MPLLCON value
SetSysFclk( save_MPLLCON );
PlayStatus.Status = DEVICE_FREE;
ReleaseDMA( PlayStatus.DevReq );
DisableIrq( BIT_DMA2 );
return MMSYSERR_NOERROR;
}
MMRESULT waveOutPrepareHeader( HWAVEOUT hwo , LPWAVEHDR pwh , UINT cbwh )
{
if ( ( PlayStatus.handle != hwo ) || ( PlayStatus.Status != DEVICE_PLAY ) )
return MMSYSERR_INVALHANDLE;
pwh->lpNext = 0;
pwh->dwBytesRecorded = 0;
pwh->dwUser = 0;
pwh->dwFlags = 0;
return MMSYSERR_NOERROR;
}
MMRESULT waveOutUnprepareHeader( HWAVEOUT hwo , LPWAVEHDR pwh , UINT cbwh )
{
if ( ( PlayStatus.handle != hwo ) || ( PlayStatus.Status != DEVICE_PLAY ) )
return MMSYSERR_INVALHANDLE;
return MMSYSERR_NOERROR;
}
MMRESULT waveOutWrite( HWAVEOUT hwo , LPWAVEHDR pwh , UINT cbwh )
{
if ( ( PlayStatus.handle != hwo ) || ( PlayStatus.Status != DEVICE_PLAY ) )
return MMSYSERR_INVALHANDLE;
if ( !PlayTotBlks )
{
lpPlayFstBlk = pwh;
lpPlayCurBlk = lpPlayFstBlk;
StartPlay();
}
else
{
lpPlayLstBlk -> lpNext = pwh ;
}
lpPlayLstBlk = pwh;
pwh->lpNext = 0;
PlayTotBlks++;
return MMSYSERR_NOERROR;
}
MMRESULT waveOutSetVolume( HWAVEOUT hwo , DWORD dwVolume )
{
if ( ( PlayStatus.handle != hwo ) || ( PlayStatus.Status != DEVICE_PLAY ) )
return MMSYSERR_INVALHANDLE;
PlayVolume = dwVolume & 0xffff;
AdjVolume( PlayVolume );
return MMSYSERR_NOERROR;
}
MMRESULT waveOutGetVolume( HWAVEOUT hwo , LPDWORD pdwVolume )
{
if ( ( PlayStatus.handle != hwo ) || ( PlayStatus.Status != DEVICE_PLAY ) )
return MMSYSERR_INVALHANDLE;
*pdwVolume = PlayVolume;
return MMSYSERR_NOERROR;
}
MMRESULT waveOutPause( HWAVEOUT hwo )
{
if ( ( PlayStatus.handle != hwo ) || ( PlayStatus.Status != DEVICE_PLAY ) )
return MMSYSERR_INVALHANDLE;
PlayPause( 1 );
return MMSYSERR_NOERROR;
}
MMRESULT waveOutRestart( HWAVEOUT hwo )
{
if ( ( PlayStatus.handle != hwo ) || ( PlayStatus.Status != DEVICE_PLAY ) )
return MMSYSERR_INVALHANDLE;
PlayPause( 0 );
return MMSYSERR_NOERROR;
}
MMRESULT waveOutReset( HWAVEOUT hwo )
{
if ( ( PlayStatus.handle != hwo ) || ( PlayStatus.Status != DEVICE_PLAY ) )
return MMSYSERR_INVALHANDLE;
return MMSYSERR_NOERROR;
}
//==========================================================
static __inline void SetPlayDma( void )
{
// WrUTXH0('@');
SetDMARun( PlayStatus.DevReq | DMA_START , ( U32 ) lpPlayCurBlk->lpData , ( U32 ) IISFIFO ,
lpPlayCurBlk->dwBufferLength / 2 );
}
static void StartPlay( void )
{
SetPlayDma();
rIISPSR = CodecPara[PlayStatus.FsIdx].PreScaler;
rIISCON = ( 1 << 5 ) + ( 0 << 4 ) + ( 0 << 3 ) + ( 1 << 2 ) + ( 1 << 1 ); //Tx DMA enable[5], Rx idle[2], Prescaler enable[1]
rIISMOD = ( 0 << 8 ) +
( 2 << 6 ) +
( 0 << 5 ) +
( 1 << 4 ) +
( ( PlayStatus.wBitsPerSample >> 4 ) << 3 ) +
( CodecPara[PlayStatus.FsIdx].ofs << 2 ) +
( 1 << 0 );
rIISFCON = ( 1 << 15 ) + ( 1 << 13 );
rIISCON |= 0x1;
}
static void __irq PlayDMA2Done( void )
{
ClearPending( BIT_DMA2 ); //Clear pending bit
lpPlayCurBlk->dwLoops--;
if ( lpPlayCurBlk->lpNext )
{
lpPlayCurBlk = lpPlayCurBlk->lpNext;
}
else
{
lpPlayCurBlk = lpPlayFstBlk;
}
SetPlayDma();
}
/************************* Record Function *********************/
static __inline void SetRecDma( void )
{
// WrUTXH0('.');
SetDMARun( RecStatus.DevReq | DMA_START , ( U32 ) IISFIFO , ( U32 ) lpRecCurBlk->lpData ,
lpRecCurBlk->dwBufferLength / 2 );
}
static void __irq RecDMADone( void )
{
if ( ( RecStatus.DevReq & 0xff ) == 0x12 )
ClearPending( BIT_DMA1 ); //Clear pending bit
if ( ( RecStatus.DevReq & 0xff ) == 0x21 )
ClearPending( BIT_DMA2 );
lpRecCurBlk->dwBytesRecorded = lpRecCurBlk->dwBufferLength;
if ( lpRecCurBlk->lpNext )
{
lpRecCurBlk = lpRecCurBlk->lpNext;
}
else
{
lpRecCurBlk = lpRecFstBlk;
}
SetRecDma();
}
MMRESULT waveInOpen( LPHWAVEIN phwi , UINT uDeviceID , LPWAVEFORMATEX pwfx , DWORD dwCallback ,
DWORD dwCallbackInstance , DWORD fdwOpen )
{
U8 i;
U8 err = 0;
if ( pwfx->wFormatTag != WAVE_FORMAT_PCM ) //only support PCM
err = 1;
if ( pwfx->nChannels != 2 ) //must be stero
err = 2;
if ( pwfx->wBitsPerSample % 8 ) //8 or 16 bits
err = 3;
for ( i = 0; i < 7; i++ )
if ( pwfx->nSamplesPerSec == CodecPara[i].Freq )
break;
if ( i == 7 )
err = 4;
if ( ( pwfx->nChannels * pwfx->wBitsPerSample ) / 8 != pwfx->nBlockAlign )
err = 5;
if ( pwfx->nAvgBytesPerSec != pwfx->nSamplesPerSec * pwfx->nBlockAlign )
err = 6;
if ( err )
{
//printf("check err = %d\n", err);
return WAVERR_BADFORMAT; //check format parameters
}
if ( RecStatus.Status != DEVICE_FREE )
return MMSYSERR_BADDEVICEID;
RecStatus.DevReq = RequestDMA( REC_DMA_ATTR , REC_DMA_MODE );
if ( RecStatus.DevReq == REQUEST_DMA_FAIL )
return MMSYSERR_BADDEVICEID;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -