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

📄 ad1836.cpp

📁 vdk audio driver example
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* =============================================================================
 *
 *  Description: This is a C++ implementation of a VDK Device Driver for AD1836
 *
 * -----------------------------------------------------------------------------
 *  Comments:
 *
 * ===========================================================================*/

#include <cdefBF533.h>
#include <ccblkfn.h>
#include <sysreg.h>
#include "AD1836.h"
#include "Talkthrough.h"

#ifdef VDK_INCLUDE_IO_

/* preprocessor macros */

#define MAX_DEVICES 1
#define READ_MODE   (1 << 0)
#define WRITE_MODE  (1 << 1)
#define DIM(x) (sizeof(x)/sizeof((x)[0]))

/* globals */

/* statics */

// array for registers to configure the ad1836
// names are defined in "Talkthrough.h"
static short sCodec1836TxRegs[] =
{									
	DAC_CONTROL_1	| 0x010, // 16-bit, 48kHz
	DAC_CONTROL_2	| 0x000,
	DAC_VOLUME_0	| 0x3ff,
	DAC_VOLUME_1	| 0x3ff,
	DAC_VOLUME_2	| 0x3ff,
	DAC_VOLUME_3	| 0x3ff,
	DAC_VOLUME_4	| 0x3ff,
	DAC_VOLUME_5	| 0x3ff,
	ADC_CONTROL_1	| 0x100, // High-pass filter on,48KHz
	ADC_CONTROL_2	| 0x020, // 16-bit
	ADC_CONTROL_3	| 0x000
};

/* externs */

/* class variables */

volatile unsigned short AD1836::c_vDma1IrqStatus[MAX_DEVICES];
volatile unsigned short AD1836::c_vDma2IrqStatus[MAX_DEVICES];
volatile short *AD1836::c_nextRxAddr;
volatile short  AD1836::c_nextRxCount;
volatile short *AD1836::c_nextTxAddr;
volatile short  AD1836::c_nextTxCount;

//--------------------------------------------------------------------------//
// Function:	init1836()													//
//																			//
// Description:	This function sets up the SPI port to configure the AD1836. //
//				The content of the array pRegWords is sent to the codec.	//
//																			//
//--------------------------------------------------------------------------//
static void init1836(
	bool           reset,
	short vRegWords[],
	int            numRegWords
)
{
	// Reset of the codec is optional
	if (reset)
	{
		// Toggle bit 0 of Port A low to reset the AD1836
		*pFlashA_PortA_Data = 0x00;
		*pFlashA_PortA_Data = 0x01;
		
		// Wait for the AD1836 to recover from reset
		for (int i=0; i<0xf000; i++);
	}

	// Configure the SPI port for control communication with the AD1836
	*pSPI_FLG = FLS4;                       // Select SPI slave device 4
	*pSPI_BAUD = 16;                        // Set baud rate SCK = HCLK/(2*SPIBAUD) SCK = 2MHz
	*pSPI_CTL = TIMOD_DMA_TX | SIZE | MSTR; // DMA write, 16-bit data, MSB first, SPI Master
	
	// Set up DMA5 to transmit to the AD1836 over the SPI port
	*pDMA5_PERIPHERAL_MAP = 0x5000;        // Map DMA5 to SPI
	*pDMA5_CONFIG         = WDSIZE_16;     // 16-bit transfers
	*pDMA5_START_ADDR     = vRegWords;     // Start address of data buffer
	*pDMA5_X_COUNT        = numRegWords;   // DMA inner loop count
	*pDMA5_X_MODIFY       = sizeof(short); // Inner loop address increment
	
	// Enable DMA5
	*pDMA5_CONFIG = WDSIZE_16 | DMAEN;

	// Enable the SPI port
	*pSPI_CTL = TIMOD_DMA_TX | SIZE | MSTR | SPE;
	
	// Wait until dma transfers for SPI are finished 
	while (DMA_RUN & *pDMA5_IRQ_STATUS);
	
	 // Wait for 2 successive lows on TXS, then wait for SPIF to go low
	while ((*pSPI_STAT & TXS) || (*pSPI_STAT & TXS));
	while (*pSPI_STAT & SPIF);
	
	// Disable the SPI port
	*pSPI_CTL = 0x0000;
}

/******************************************************************************
 * Dispatch Function for the AD1836 Device Driver
 *
 * This function is called for all device-driver operations.
 * It "fans-out" to a specific function for each of the supported
 * operations.
 */
 
void*
AD1836::DispatchFunction(VDK::DispatchID inCode, VDK::DispatchUnion &inUnion)
{
    int    ret_val = 0;
    switch(inCode)
    {
        case VDK::kIO_Init:      
        	Init(inUnion);
            break;
        case VDK::kIO_Activate:  
        	Activate(inUnion);
            break;
        case VDK::kIO_Open:      
        	ret_val = Open(inUnion);
            break;
        case VDK::kIO_Close:     
        	ret_val = Close(inUnion);
            break;
        case VDK::kIO_SyncRead:      
        	ret_val = SyncRead(inUnion);
            break;
        case VDK::kIO_SyncWrite:     
        	ret_val = SyncWrite(inUnion);
            break;
        case VDK::kIO_IOCtl:
        	ret_val = IOCtl(inUnion);
            break;
        default:
                /* Put invalid DeviceDispatchID code HERE */
            break;
    }
    return reinterpret_cast<void *>(ret_val);
}


//
// This function runs during VDK startup (i.e. before any threads are
// running) and performs the initialization necessary both for the
// driver object and for the hardware itself.
//
void AD1836::Init (const VDK::DispatchUnion &inUnion)
{
	// Get the instance number from the boot I/O object initializer
	m_devNo = *((long *)inUnion.Init_t.pInitInfo);
	
	// Initialize the driver's member variables.
	m_sampleBytes = 2;
	m_readFlags  = 0;
	m_writeFlags = 0;
	m_DevFlagRead  = VDK::CreateDeviceFlag();
	m_DevFlagWrite = VDK::CreateDeviceFlag();
	m_vReadCurrBuffCount  = 0;
	m_vReadNextBuffCount  = 0;
	m_vWriteCurrBuffCount = 0;
	m_vWriteNextBuffCount = 0;

	// Initialize and enable asynchronous memory banks in the
	// External Bus Interface Unit so that Flash A can be accessed.
	*pEBIU_AMBCTL0	= 0x7bb07bb0;
	*pEBIU_AMBCTL1	= 0x7bb07bb0;
	*pEBIU_AMGCTL	= 0x000f;

	// Set bit 0 or flash port A to output
	*pFlashA_PortA_Dir = 0x1;

	// Set Sport0 RX (DMA1) and TX (DMA2) interrupt priority to 2 = IVG9 
	*pSIC_IAR1 = (*pSIC_IAR1 & 0xfffff00f) | 0x00000220;
	
	// enable Sport0 RX and TX interrupts
	*pSIC_IMASK |= 0x00000600;
}


//
// This function is responsible for the setup of the device
// driver each time a thread calls VDK::OpenDevice() on it.
//
// The control string for the driver may specify a number of
// flags to control the initialisation and operation of the
// device. Some of these are global to the device and hence
// affect both the read and write sides, others may be
// specified (or not) independently for read and write.
//
//	R - open for reading (audio input)
//	W - open for writing (audio output)
//	F - force codec reset, only if device not already open
//	S - stereo mode, one channel pair (1L & 1R) - the default
//	Q - quadraphonic mode, two channel pairs (1L, 1R, 2L & 2R)
//
// At present the sample rate is fixed at 48KHz and the sample
// width at 16 bits. A future update to the driver will add
// control-string flags to enable 96KHz sampling and 20 or 24 bits
// sample width.
//
// The device may be opened for both reading and writing - by
// specifying "RW" in the control string - or may be opened
// separately for reading and writing, usually by different
// threads. The latter case is known as "split-open" and will
// normally be the most useful when dealing with streaming
// audio data.
//  
int AD1836::Open (const VDK::DispatchUnion &inUnion)
{
	unsigned mode = 0;
	bool forceReset = true;
	unsigned short xse = 0;
	
	// Parse the mode string
	char *pStr = inUnion.OpenClose_t.flags;

	while (*pStr)
	{
		switch (*pStr)
		{
			default:
				return -1;	// unknown option
			case 'R': case 'r':
				mode |= READ_MODE;
				break;
			case 'W': case 'w':
				mode |= WRITE_MODE;
				break;
			case 'F': case 'f':
				forceReset = true;
				break;
			case 'N': case 'n':
				forceReset = false;
				break;
			case 'Q': case 'q': // Quadraphonic (4 channels)
				xse = 0x100;    // TXSE/RXSE bit set
				break;
			case 'S': case 's': // Stereo (2 channels)
				xse = 0x0;      // TXSE/RXSE bit clear
				break;
			case ' ': case '\t': case ',':
				break;		// ignore punctuation and whitespace
		}
		++pStr;
	}

	// openMode is the current "overall" state of the driver
	unsigned openMode = m_readFlags | m_writeFlags;

	// The driver only allows one open for reading and one for writing
	if (mode & openMode & (READ_MODE | WRITE_MODE))
		return -1; 			// already open in this mode

	// Initialisation of the codec is only performed if the device is
	// not currently open.
	if (0 == openMode)  	// Not open yet
	{
		// Setup the codec's internal registers
		init1836(forceReset, sCodec1836TxRegs, DIM(sCodec1836TxRegs));
	}

	// Store the open mode in the device handle
	*inUnion.OpenClose_t.dataH = reinterpret_cast<void*>(mode);

	// Read-specific initialisations
	if (mode & READ_MODE)
	{
		// Sport0 receive configuration
		*pSPORT0_RCR1 = RFSR | LRFS | RCKFE;   // Ext. CLK, Ext. Frame sync, MSB first, Active Low
		*pSPORT0_RCR2 = SLEN_16 | RSFSE | xse; // 16-bit data, Stereo frame sync enable

		// Map DMA1 to Sport0 RX
		*pDMA1_PERIPHERAL_MAP = 0x1000;
		
		m_readBuffers = 0;
		m_readFlags = mode;
	}

	// Write-specific initialisations
	if (mode & WRITE_MODE)
	{
		// Sport0 transmit configuration
		*pSPORT0_TCR1 = TFSR | LTFS | TCKFE;   // Ext. CLK, Ext. Frame sync, MSB first, Active Low
		*pSPORT0_TCR2 = SLEN_16 | TSFSE | xse; // 16-bit data, Stereo frame sync enable
		

⌨️ 快捷键说明

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