📄 audiodriver.c
字号:
// Copyright(c) 2005 Analog Devices, Inc. All Rights Reserved.
// This software is proprietary and confidential to Analog Devices, Inc. and its licensors.
// File : $Id: //depot/Development/VisualAudio/Platforms/EZKit_BF533_Basic/2.5.0/AudioDriver.c#4 $
// Part of : VisualAudio V2.5.0
// Updated : $Date: 2006/12/04 $ by $Author: blee $
/*****************************************************************************************************
Description: Configures the TDM 8 channel audio mode through the AD1836 driver.
The audio data is received from the ADC and stored into the buffer iADCdata.
The output data is transmitted from the buffer iDACdata.
One dimensional buffer, rxBuffer, is provided for the ADC data, and another circular
buffer, txBuffer, is for the DAC data. A double buffering scheme
is implemented so that data in one half is available for processing while the other
half is used for DMA operations. The copying of data from the DMA
buffers to/from the post-processing buffer is done by the user function
DoProcessing().
The Audio Handling is invoked through the separate
interrupt thread for the function, or directly called by ProcessAudioCallback()
depending on the RENDER_AT_LOWER_INTERRUPT_LEVEL definition.
******************************************************************************************************/
/*********************************************************************
Include files
*********************************************************************/
#include "Basic.h"
#include <drivers/codec/adi_ad1836a_ii.h>
#include <drivers/sport/adi_sport.h>
#include "AudioDriver.h"
#include <string.h>
/*********************************************************************
Local variables
*********************************************************************/
// handle to the AD1836 driver
static ADI_DEV_DEVICE_HANDLE DriverHandle;
// device manager handle
extern ADI_DEV_MANAGER_HANDLE DevMgrHandle; // handle for the device manager
// DMA manager handle
extern ADI_DMA_MANAGER_HANDLE DMAMgrHandle; // handle for the DMA manager
// double buffer for processing SPORT TDM RX/TX data
section("slowsdata_noncached")
static ADI_DEV_1D_BUFFER rxBuffer_1, rxBuffer_2;
section("slowsdata_noncached")
static ADI_DEV_1D_BUFFER txBuffer_1, txBuffer_2;
// storage for audio PCM data
#if (DMA_BUFFER_IN_L1_MEMORY && Layout1_TICK_SIZE <= 32)
section("L1_dma_a")
#else
section("slowsdata_noncached")
#endif
static int iADCdata[TDM_FRAME_SIZE * Layout1_TICK_SIZE * 2]; // 2: double buffering
#if (DMA_BUFFER_IN_L1_MEMORY && Layout1_TICK_SIZE <= 32)
section("L1_dma_b")
#else
section("slowsdata_noncached")
#endif
static int iDACdata[TDM_FRAME_SIZE * Layout1_TICK_SIZE * 2]; // 2: double buffering
/*********************************************************************
Exported buffers
*********************************************************************/
// pointer array that contains base channel pointer of iDACdata for the transmit buffer
static int *pOutputSampleBasePtr[SYSAudio_MAX_OUTPUT_CHANNEL_COUNT * 2]; // 2: double buffering
// pointer array that contains base channel pointer of iADCdata for the receive buffer
static int *pInputSampleBasePtr[SYSAudio_MAX_INPUT_CHANNEL_COUNT * 2]; // 2: double buffering
#if (RENDER_AT_LOWER_INTERRUPT_LEVEL)
#include <signal.h>
#endif
static int gWhichBuffer;
/*********************************************************************
Function: FWRender
Description: This is the user interrupt service routine which
runs on user interrupt 0 (or simple function, depending on
conditional compilation macro RENDER_AT_LOWER_INTERRUPT_LEVEL.
It simply calls the glue function
for the DSP to handle input data.
*********************************************************************/
#if (RENDER_AT_LOWER_INTERRUPT_LEVEL)
// user interrupt 0 ISR
ADI_INT_HANDLER(FWRender)
#else
static void FWRender(void)
#endif
{
// call VisualAudio layout processing function
int **pOutputPtrs, **pInputPtrs;
// switch ping pong variable for double buffering
if (gWhichBuffer == 1) // indicating first portion is transferred
{
// first DMA buffer
pInputPtrs = &pInputSampleBasePtr[0];
pOutputPtrs = &pOutputSampleBasePtr[0];
}
else // indicating second portion is transferred
{
// second DMA buffer
pInputPtrs = &pInputSampleBasePtr[SYSAudio_MAX_INPUT_CHANNEL_COUNT];
pOutputPtrs = &pOutputSampleBasePtr[SYSAudio_MAX_OUTPUT_CHANNEL_COUNT];
}
DoProcessing(pInputPtrs,pOutputPtrs);
#if (RENDER_AT_LOWER_INTERRUPT_LEVEL)
return (ADI_INT_RESULT_PROCESSED);
#endif
}
/*********************************************************************
Function: ProcessAudioCallback
Description: Each type of callback event has it's own unique ID
so we can use a single callback function for all
callback events. The switch statement tells us
which event has occurred.
Note that in the device driver model, in order to
generate a callback for buffer completion, the
CallbackParameter of the buffer must be set to a non-NULL
value. In the current DMA chained loopback mode,
given paramter is passed to the function indicating
which buffer has been completed.
*********************************************************************/
#ifndef NO_OPTIMIZE
#pragma optimize_for_speed
#endif
void ProcessAudioCallback(void* AppHandle, u32 Event, void* pArg)
{
switch (Event)
{
// CASE (DMA buffer processed)
case ADI_DEV_EVENT_BUFFER_PROCESSED:
///////////////////////////////////////////////////////////////////////////////////////////////
// FIXME : used temporarily until the service library fixes this problem
// in case we are in the middle of fetching descriptor
while ((*pDMA1_IRQ_STATUS & 0x0004) != 0) asm ("nop;");
// read next descriptor and get the callback parameter to identify which buffer
gWhichBuffer = (int)(((ADI_DEV_1D_BUFFER*)(*pDMA1_NEXT_DESC_PTR))->CallbackParameter);
///////////////////////////////////////////////////////////////////////////////////////////////
#if (RENDER_AT_LOWER_INTERRUPT_LEVEL)
// call other interrupt for rendering
raise(USER_ISR0);
#else
// call VisualAudio layout processing function
FWRender();
#endif
break;
case ADI_DEV_EVENT_SUB_BUFFER_PROCESSED:
break;
case ADI_DEV_EVENT_DMA_ERROR_INTERRUPT:
ErrorMessage("DMA error interrupt\n");
break;
}
}
/*********************************************************************
Function: resolveChannelPointers
Description: To simplify the process of reformatting DMA ADC or DAC data
into/from the working buffer, it assign each element
of an pointer array with valid base channel pointers
to iDACdata and iADCdata buffer.
*********************************************************************/
// initialize the pointers to the DMA ADC/DAC buffer for double buffering
#ifndef NO_OPTIMIZE
#pragma optimize_for_space
#endif
static void resolveChannelPointers(void)
{
int i;
//=====================================================
// Output channels
//=====================================================
// Analog channels
pOutputSampleBasePtr[0] = &iDACdata[INTERNAL_DAC_L1];
pOutputSampleBasePtr[1] = &iDACdata[INTERNAL_DAC_R1];
pOutputSampleBasePtr[2] = &iDACdata[INTERNAL_DAC_L2];
pOutputSampleBasePtr[3] = &iDACdata[INTERNAL_DAC_R2];
pOutputSampleBasePtr[4] = &iDACdata[INTERNAL_DAC_L3];
pOutputSampleBasePtr[5] = &iDACdata[INTERNAL_DAC_R3];
// set up the buffer pointers for the second half of the double buffer
for (i = 0; i < SYSAudio_MAX_OUTPUT_CHANNEL_COUNT; i++)
pOutputSampleBasePtr[SYSAudio_MAX_OUTPUT_CHANNEL_COUNT + i] =
pOutputSampleBasePtr[i] + (TDM_FRAME_SIZE * Layout1_TICK_SIZE);
//=====================================================
// Input channels
//=====================================================
// Analog channels
pInputSampleBasePtr[0] = &iADCdata[INTERNAL_ADC_L1];
pInputSampleBasePtr[1] = &iADCdata[INTERNAL_ADC_R1];
pInputSampleBasePtr[2] = &iADCdata[INTERNAL_ADC_L2];
pInputSampleBasePtr[3] = &iADCdata[INTERNAL_ADC_R2];
// set up the buffer pointers for the second half of the double buffer
for (i = 0; i < SYSAudio_MAX_INPUT_CHANNEL_COUNT; i++)
pInputSampleBasePtr[SYSAudio_MAX_INPUT_CHANNEL_COUNT + i] =
pInputSampleBasePtr[i] + (TDM_FRAME_SIZE * Layout1_TICK_SIZE);
}
//////////////////////////////////////////////////////////////////////
// workaround for audio reset
// addresses for Port B in Flash A (used for resetting the codec)
#define pFlashA_PortA_Dir (volatile unsigned char *)0x20270006
#define pFlashA_PortA_Data (volatile unsigned char *)0x20270004
static void reset_AD1836(void)
{
int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -