⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ac97.c

📁 基于ADSP-BF535 USB驱动应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*----------------------------------------------------------------------------------
*
* COPYRIGHT (c) 2001 by Singing Electrons, Inc. All rights reserved.
*
* Module Name			: C:\se\adi\audioclass\vdsp\ac97.c
*
* Description			: Contains code to communicate with the AC97 AC-Link
*
*
* Revision History	: At bottom of the file.
*
*---------------------------------------------------------------------------------*/

/** include files **/
#include <sys/exception.h>
#include <sys/excause.h>
#include <defBF535.h>
#include "dtype.h"
#include "register.h"
#include "dprintf.h"
#include "dmablocks.h"
#include "ac_init.h"
#include "ac97.h"

/** local definitions **/
//This is for Eagle-35 only!
#define kLEDSet	\
		ZET(bPF8,1)+\
		ZET(bPF9,1)+\
		ZET(bPF10,1)+\
		ZET(bPF11,1)+\
		ZET(bPF12,1)+\
		ZET(bPF13,1)+\
		ZET(bPF14,1)

#define kLEDMix \
		ZET(bPF8,0)+\
		ZET(bPF9,1)+\
		ZET(bPF10,0)+\
		ZET(bPF11,1)+\
		ZET(bPF12,0)+\
		ZET(bPF13,1)+\
		ZET(bPF14,0)

#define bACRes		15
#define kACResSet	ZET(bACRes,1)     	
#define kACResReset	ZET(bACRes,0)     	


// Define time constants

// (not yet bound to core clock frequency but you rather have to change here for 
// now)

#define TC_1MS_300MHZ	300000
#define TC_2US_300MHZ	600
#define TC_3S_300MHZ	20000000


#define FRAME_BUFFER_LEN (16 * 2)
#define CODEC_REG_INIT_COUNT 25
#define	CODEC_REG_INIT_LENGTH	(CODEC_REG_INIT_COUNT * 2)

enum {
	AC97_STATE_UNDEFINED = 0,
	AC97_STATE_INITIALIZING_CODEC_STARTED,
	AC97_STATE_INITIALIZING_CODEC_COMPLETED,
	AC97_STATE_PLAY_DATA,
};

/* default settings */
USHORT gInitCodecRegs[CODEC_REG_INIT_LENGTH] =
	{
	REGS_RESET,		0xFFFF, // Writing any value to this reg. 
					// performs a register reset
	MASTER_VOLUME,		0x0000,	// Mute off master volume, 0 dB gain on 
					// L/R channels
	HEAD_VOLUME,	    	0x0000,	// Mute off headphone volume, 6 dB gain
	MASTER_VOLUME_MONO,	0x8000, // Mute on mono master volume
	PC_BEEP_Volume,	    	0x8000, // Mute on PC beep volume
	PHONE_Volume,	    	0x8008, // Mute on phone volume, 0 dB gain
	MIC_Volume,		0x8008, // Mute on MIC volume, 0 dB gain
	LINE_IN_Volume,	    	0x8808, // Mute on LINE in vol.,0 dB gain on L/R
	CD_Volume,		0x8808, // Mute on CD volume, 0 dB gain on L/R
	VIDEO_Volume,	    	0x8808, // Mute on video volume,0 dB gain on L/R
	AUX_Volume,		0x8808, // Mute on aux volume,0 dB gain on L/R
	PCM_OUT_Volume,	    	0x0F0F,	// Mute off, -10.5 dB gain 
#ifndef MIC_IN
	RECORD_SELECT,	    	0x0404,	// Selected LINE in L/R as Record Select 
#else
	RECORD_SELECT,	    	0x0000,	// Selected MIC1 as Record Select 
#endif
	RECORD_GAIN,	    	0x0000,	// Mute off, 0 dB record gain 
	GENERAL_PURPOSE,	0x0000,	// Codec loopback off,MIC1 selected,
					// Mono output selected: Mix
					// PHAT stereo off,pre-3D
	THREE_D_CONTROL_REG,    0x0000, // 3D depth: 0%
	POWERDOWN_CTRL_STAT,    0x0000, // Status reg. to see powered-down
					// subsections
	EXTEND_AUDIO_ID,	0x0001, // Read-only reg. support for variable
					// rate audio
	EXTEND_AUDIO_CTL,	0x0000, // Enable support for variable rate audio
	SAMPLE_RATE_GENERATE_1, 0xBB80,	// DAC Sample Rate 48.000 KHz
	SAMPLE_RATE_GENERATE_0, 0xBB80, // ADC Sample Rate 48.000 KHz
	JACK_SENSE,		0x0000, // No sense interrupts enabled
	MISC_CONTROL_BITS,	0x0404, // DAC:SR1 selected,ADC:SR0 selected
	VENDOR_ID_1,	    	0x4144, // Read-only string
	VENDOR_ID_2,	    	0x5360 // Read-only string
	};



/** external functions **/

/** external data **/

/** internal functions **/

/** public data **/
UINT gDataBufferHead;
UINT gDataBufferTail;
UCHAR gDataBuffer[MAX_DATA_BUFFER_SIZE];

/** private data **/
static USHORT *gpRxBuffer;
static USHORT *gpTxBuffer;
static USHORT gCodecInitResults[CODEC_REG_INIT_LENGTH];
static UINT gCurrentAC97State;
static UINT gInterruptCount;

static USHORT gTxBuffer[FRAME_BUFFER_LEN >> 1];
static USHORT gRxBuffer[FRAME_BUFFER_LEN >> 1];

/** public functions **/

/** private functions **/
static void CodecReset (void);
static void InitSPORT0 (void);
static void InitSPORT0DMA (void *pTxBuffer, void *pRxBuffer);
static void InitCodec (void);
EX_INTERRUPT_HANDLER  (AC97_ISR);



bool AC97_Init (void)
	{
		UINT chipVer;

		gCurrentAC97State = AC97_STATE_UNDEFINED;
		gInterruptCount = 0;
		gDataBufferHead = gDataBufferTail = 0;
		memset (&gDataBuffer, 0, sizeof (gDataBuffer));

		gpRxBuffer = &gRxBuffer[0];//AllocDMABlock (FRAME_BUFFER_LEN);
		gpTxBuffer = &gTxBuffer[0];//AllocDMABlock (FRAME_BUFFER_LEN);

		if ((gpRxBuffer == nil) || (gpTxBuffer == nil))
			return( false);

		//Initialize the Tx Buffer with defaults
		memset (gpTxBuffer, 0, FRAME_BUFFER_LEN);
		gpTxBuffer[oTagPhase >> 1] = kVldFrm|kVldCmd|kVldAddr;
		gpTxBuffer[oCmdAddrSlot >> 1] = SERIAL_CONFIGURATION;
		gpTxBuffer[oCmdDataSlot >> 1] = 0x9900;

			

		CodecReset ();
		InitSPORT0 ();
		InitSPORT0DMA (gpTxBuffer, gpRxBuffer);

		
		// install the interrupt handler 
		//register_handler(ik_ivg8, AC97_ISR);
		register_handler(ik_ivg7, AC97_ISR);
		chipVer = 0xf0000000 & chipId_REG;
  
	  
	  if(chipVer) 
	  	{
	    	// rev. 1.0 or higher
		    SIC_IMASK_REG |= SIC_MASK4; //SPORT0 RX DMA
		  } 
		else 
			{
	    	// rev. 0.x
	    	SIC_IMASK_REG &= ~(SIC_MASK4);
	   	}

	  asm("ssync;");

	  //IMASK_REG |= 0x0100; // unmask IVG 8 at core
	  IMASK_REG |= 0x0080; // unmask IVG 7 at core
	  asm("ssync;");

		gCurrentAC97State = AC97_STATE_INITIALIZING_CODEC_STARTED;
		InitCodec ();
		gCurrentAC97State = AC97_STATE_INITIALIZING_CODEC_COMPLETED;;

		return (true);
		
		
	}


/*------------------------------------------------------------
*	EnablePlayback
*
*	Parameters:  
*
*	Globals Used:
*		None
*
*	Description:
*		Enable playback on the codec.
*
*	Returns:
*
*
*------------------------------------------------------------*/
void AC97_EnablePlayback (void)
	{
		gpTxBuffer[oLeft >> 1] = 0;
		gpTxBuffer[oRght >> 1] = 0;
		gpTxBuffer[oTagPhase >> 1] = kVldFrm | kVldLeft | kVldRight;
		gCurrentAC97State = AC97_STATE_PLAY_DATA;
	}


/*------------------------------------------------------------
*	EnablePlayback
*
*	Parameters:  
*
*	Globals Used:
*		None
*
*	Description:
*		Disable playback on the codec.
*
*	Returns:
*
*
*------------------------------------------------------------*/
void AC97_DisablePlayback (void)
	{
		gCurrentAC97State = AC97_STATE_INITIALIZING_CODEC_COMPLETED;
		gpTxBuffer[oLeft >> 1] = 0;
		gpTxBuffer[oRght >> 1] = 0;
		gpTxBuffer[oLeft >> 1] = 0;
		gpTxBuffer[oRght >> 1] = 0;
	}



/*------------------------------------------------------------
*	AC97_SetVolumeAndMute
*
*	Parameters:  
*
*	Globals Used:
*		None
*
*	Description:
*		This routine sets the line-out volume and mute!
*
*	Returns:
*
*
*------------------------------------------------------------*/
void AC97_SetVolumeAndMute (USHORT leftVol, USHORT rightVol, UCHAR mute)
	{
		UCHAR leftVolB;
		UCHAR rightVolB;
		USHORT regData;
		UINT interruptCount;

		if (leftVol != 0)
			leftVolB = (UCHAR)(((~(USHORT)leftVol) & 0xffff) / (USHORT)0x180);
		else
			leftVolB = 0;

		if (rightVol != 0)
			rightVolB = (UCHAR)(((~(USHORT)rightVol) & 0xffff) / (USHORT)0x180);
		else
			rightVolB = 0;


		regData = ((mute == 0) ? 0x0000 : 0x8000) | (((USHORT)leftVolB & 0x3f) << 8) | rightVolB & 0x3f;

		Dprintf2 ("l: %4x, r: %4x", leftVol, rightVol);
		Dprintf1 ("RegData: %4x", regData);
		
		gpTxBuffer[oCmdAddrSlot >> 1] = MASTER_VOLUME;
		gpTxBuffer[oCmdDataSlot >> 1] = regData;
		//Now it's safe to say we've got address and data
		gpTxBuffer[oTagPhase >> 1] |= (kVldCmd|kVldAddr); //we've got commands coming in

		//Wait for atleast two SPORT interrupt
		interruptCount = gInterruptCount;
		
		while (interruptCount == gInterruptCount)
			asm ("nop;");
		
		//Wait for atleast two SPORT interrupt
		interruptCount = gInterruptCount;
		
		while (interruptCount == gInterruptCount)
			asm ("nop;");

		//Now it's safe to say we've got address and data
		gpTxBuffer[oTagPhase >> 1] &= ((USHORT)~(kVldCmd|kVldAddr)); //we've removed the commands now!

	}

/*------------------------------------------------------------
*	CodecReset
*
*	Parameters:  
*
*	Globals Used:
*		None
*
*	Description:
*		This routine resets the codec.
*
*	Returns:
*
*
*------------------------------------------------------------*/
void CodecReset (void)
	{
		UINT countdown;
				
		FIO_DIR_REG = kLEDSet + kACResSet; // set output pins
	  asm("ssync;");

		FIO_FLAG_S_REG = kLEDSet + kACResSet; // turn LEDs on,AC not yet in reset
	  asm("ssync;");

		countdown = TC_1MS_300MHZ;
		while (countdown)
			countdown--;

		FIO_FLAG_C_REG = kLEDSet+kACResSet;	// assert AD1885 /RESET (active low) 
	  asm("ssync;");

		//hold reset
		// AD1885 /Reset Active low for ca 
		// 2 usec (needs 1 us)
		// assuming 300 Mhz DSP Core

		countdown = TC_2US_300MHZ;
		while (countdown)
			countdown--;

		FIO_FLAG_S_REG = kLEDMix+kACResSet;	// De-assert AD1885 /RESET and turn on 
		// (~)half of the LEDs
	  asm("ssync;");
	
		// use another 3 seconds to allow codec to recover from reset
		// 162.8 ns needed before outputting BITCLK according to datasheet??
		countdown = TC_3S_300MHZ;
		while (countdown)
			countdown--;

		FIO_FLAG_S_REG = kLEDSet + kACResSet; // turn LEDs on
	  asm("ssync;");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -