📄 ad1836.cpp
字号:
/* =============================================================================
*
* 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 + -