www.pudn.com > LPC2148_IAR_LPC2148.zip > audio_class.c
/*************************************************************************
*
* Used with ICCARM and AARM.
*
* (c) Copyright IAR Systems 2005
*
* File name : audio_class.c
* Description : AUDIO CLASS module
*
* History :
* 1. Data : November 29, 2005
* Author : Stanimir Bonev
* Description : Create
*
* $Revision: 1.1.2.2 $
**************************************************************************/
#include "audio_class.h"
volatile Boolean SempEna,MicEna;
Int32U SempCount,SempPeriod,Delta,MicCurrBuffer;
pInt16S pSpkData,pMicData;
Int32U SempPerCurrHold,DeltaPer,MicSempCount;
const Int32U VolumeMul [] =
{
// 256 - 0
//-48dB- 0x0
261,
//-47dB- 0x1
293,
//-46dB- 0x2
328,
//-45dB- 0x3
369,
//-44dB- 0x4
414,
//-43dB- 0x5
464,
//-42dB- 0x6
521,
//-41dB- 0x7
584,
//-40dB- 0x8
655,
//-39dB- 0x9
735,
//-38dB- 0xA
825,
//-37dB- 0xB
926,
//-36dB- 0xC
1039,
//-35dB- 0xD
1165,
//-34dB- 0xE
1308,
//-33dB- 0xF
1467,
//-32dB- 0x10
1646,
//-31dB- 0x11
1847,
//-30dB- 0x12
2072,
//-29dB- 0x13
2325,
//-28dB- 0x14
2609,
//-27dB- 0x15
2927,
//-26dB- 0x16
3285,
//-25dB- 0x17
3685,
//-24dB- 0x18
4135,
//-23dB- 0x19
4640,
//-22dB- 0x1A
5206,
//-21dB- 0x1B
5841,
//-20dB- 0x1C
6554,
//-19dB- 0x1D
7353,
//-18dB- 0x1E
8250,
//-17dB- 0x1F
9257,
//-16dB- 0x20
10387,
//-15dB- 0x21
11654,
//-14dB- 0x22
13076,
//-13dB- 0x23
14672,
//-12dB- 0x24
16462,
//-11dB- 0x25
18471,
//-10dB- 0x26
20724,
//-9dB - 0x27
23253,
//-8dB - 0x28
26090,
//-7dB - 0x29
29274,
//-6dB - 0x2A
32846,
//-5dB - 0x2B
36854,
//-4dB - 0x2C
41350,
//-3dB - 0x2D
46396,
//-2dB - 0x2E
52057,
//-1dB - 0x2F
58409,
// 0dB - 0x30
65536,
// 1dB - 0x31
73533,
// 2dB - 0x32
82505,
// 3dB - 0x33
92572,
// 4dB - 0x34
103868,
// 5dB - 0x35
116541,
// 6dB - 0x36
130762,
};
#pragma segment="DMA_RAM"
#pragma location="DMA_RAM"
#pragma data_alignment=4
__no_init Int16S AudioSpkData[SempRerFrame * 3];
#pragma location="DMA_RAM"
#pragma data_alignment=4
__no_init Int16S AudioMicData1[SempRerFrame * 2];
#pragma location="DMA_RAM"
#pragma data_alignment=4
__no_init Int16S AudioMicData2[SempRerFrame * 2];
#pragma location="DMA_RAM"
#pragma data_alignment=4
__no_init DmaIsoPacket_t DmaSpkIsoPacket;
#pragma location="DMA_RAM"
#pragma data_alignment=4
__no_init DmaIsoPacket_t DmaMicIsoPacket;
#pragma data_alignment=4
Int8U AudioBuf[2];
Int8U AudioRequest,AudioCS,AudioCN,AudioId;
Int16U AudioDataSize;
Int16S AudioFeat1Vol;
Int32U AudioSpkVolMul;
Boolean AudioFeat1Mute;
Int16S AudioFeat2Vol;
Int32U AudioMicVolMul;
Boolean AudioFeat2Mute;
/*************************************************************************
* Function Name: AudioClassInit
* Parameters: none
*
* Return: none
*
* Description: USB Class Audio Init
*
*************************************************************************/
void AudioClassInit (void)
{
// Init Audio Class variables
SempEna =\
AudioFeat1Mute =\
AudioFeat2Mute = FALSE;
SempCount =\
AudioFeat1Vol =\
AudioFeat2Vol = 0;
pSpkData = AudioSpkData;
SempPerCurrHold = SempPeriod;
// Registered The Class Request
UsbCoreUserFuncRegistered(UsbClassAudioRequest,UsbUserClass);
// Registered User Ep0 Data receive
UsbCoreUserFuncRegistered(UsbClassAudioData,UsbClassEp0OutPacket);
// DAC Init
PINSEL1_bit.P0_25 = 2;
DACR_bit.VALUE = 0x200;
// ADC 0.3 Init
PINSEL1_bit.P0_30 = 1;
// ADC clk = 60MHz/14, Ch3
AD0CR = (1<<21) + (14 << 8) + (1<<3);
// Init System Timer - Timer0
TIMER_Init(TIMER0, TIMER_PRECISION);
SempPeriod = (1 sec_T0)/SampFreq;
DeltaPer = SempPeriod/(SempRerFrame*2);
TIMER_SetMatchAction(TIMER0, CH0, TimerAction_Interrupt | TimerAction_ResetTimer,
SempPeriod, NULL, NULL, DONOTHING);
VIC_EnaFastInt(1<Configuration == 1))
{
if(pUsbDevCtrl->Interface == 1)
{
if(pUsbDevCtrl->AlternateSetting == 0)
{
USB_RealizeEndPoint((USB_Endpoint_t)SpkEp,1,0,FALSE);
USB_UserFuncRegistered(NULL,SpkEp);
}
else if (pUsbDevCtrl->AlternateSetting == 1)
{
// Realize Class EPs
USB_RealizeEndPoint((USB_Endpoint_t)SpkEp,1,SpkEpMaxSize, FALSE);
USB_DmaInitTransfer((USB_Endpoint_t)SpkEp,SpkDDInd,(pInt32U)AudioSpkData,0,1,&DmaSpkIsoPacket,TRUE);
USB_UserFuncRegistered(AudioInHadler,SpkEp);
}
}
else if (pUsbDevCtrl->Interface == 2)
{
if(pUsbDevCtrl->AlternateSetting == 0)
{
MicEna = FALSE;
USB_RealizeEndPoint((USB_Endpoint_t)MicEp,1,0,FALSE);
USB_UserFuncRegistered(NULL,MicEp);
}
else if (pUsbDevCtrl->AlternateSetting == 1)
{
// Realize Class EPs
USB_RealizeEndPoint((USB_Endpoint_t)MicEp ,1,MicEpMaxSize, FALSE);
USB_UserFuncRegistered(AudioOutHadler,MicEp);
pMicData = AudioMicData1;
DmaMicIsoPacket.PacketLength = 0;
USB_DmaInitTransfer((USB_Endpoint_t)MicEp,
MicDDInd,
(pInt32U)&AudioMicData1,
0,
1,
&DmaMicIsoPacket,
TRUE);
MicCurrBuffer = 0;
MicEna = TRUE;
}
}
}
}
return(NULL);
}
/*************************************************************************
* Function Name: AudioInHadler
* Parameters: void * pArg
*
* Return: none
*
* Description: USB Class Audio Out EP handler
*
*************************************************************************/
void AudioInHadler (void *Arg)
{
Int32U IntHold;
pUSB_DmaDesc_t pSpkDD = USB_DmaGetDesc(SpkDDInd);
Int32U ReceievedBytes = DmaSpkIsoPacket.PacketLength;
if(ReceievedBytes)
{
pSpkData += ReceievedBytes/sizeof(Int16U);
if(pSpkData >= AudioSpkData + sizeof(AudioSpkData)/sizeof(Int16U))
{
pSpkData = AudioSpkData;
}
if(SempEna)
{
// Adapt sample rate
if (Delta > (SempRerFrame * SubFrameSize))
{
SempPerCurrHold = SempPeriod - DeltaPer;
}
else if (Delta < (SempRerFrame * SubFrameSize))
{
SempPerCurrHold = SempPeriod + DeltaPer;
}
else
{
SempPerCurrHold = SempPeriod;
}
}
else
{
if(pSpkData >= (AudioSpkData + (2*sizeof(AudioSpkData))/(3*sizeof(Int16U))))
{
// Enable output
SempCount = 0;
SempEna = TRUE;
}
}
IntHold = disable_interrupts();
Delta += ReceievedBytes;
restore_interrupts(IntHold);
}
// Load speaker buffer
pSpkDD->pDmaBuffer = (pInt32U)pSpkData;
pSpkDD->pDmaIsoPacket = &DmaSpkIsoPacket;
USB_DmaRestattTransfer((USB_Endpoint_t)SpkEp,SpkDDInd);
}
/*************************************************************************
* Function Name: AudioOutHadler
* Parameters: void * pArg
*
* Return: none
*
* Description: USB Class Audio In EP handler
*
*************************************************************************/
void AudioOutHadler (void *Arg)
{
Int32U IntHold;
if(MicEna)
{
IntHold = disable_interrupts();
// Set pointer to free buffer
if(++MicCurrBuffer & 1)
{
DmaMicIsoPacket.PacketLength = (Int32U)pMicData - (Int32U)AudioMicData1;
pMicData = AudioMicData2;
}
else
{
DmaMicIsoPacket.PacketLength = (Int32U)pMicData - (Int32U)AudioMicData2;
pMicData = AudioMicData1;
}
// Send microphone output buffer
restore_interrupts(IntHold);
USB_DmaInitTransfer((USB_Endpoint_t)MicEp,
MicDDInd,
(pInt32U)((MicCurrBuffer & 1)?AudioMicData1:AudioMicData2),
0,
1,
&DmaMicIsoPacket,
TRUE);
}
}
/*************************************************************************
* Function Name: fiq_handler
* Parameters: none
*
* Return: none
*
* Description:
*
*************************************************************************/
__fiq __arm void fiq_handler (void)
{
static union _Val
{
Int32S Data;
struct
{
Int16U DataLo;
Int16S DataHi;
};
} Val = {0x02000000};
union _Val MicTemp;
// Set DAC
DACR_bit.VALUE = Val.DataHi;
if (SempEna)
{
if(Delta > 1)
{
// Get next input sample
Val.Data = AudioSpkData[SempCount++];
Delta -= 2;
// Correct pointer to sample buffer
if(SempCount >= sizeof(AudioSpkData)/sizeof(Int16U))
{
SempCount = 0;
}
if(!AudioFeat1Mute && AudioSpkVolMul)
{
// Apply volume
Val.Data *= AudioSpkVolMul;
// Add offset
Val.DataHi += 0x200;
// Check for overflow and correct value
if(Val.DataHi < 0)
{
Val.DataHi = 0;
}
else if(Val.DataHi > 0x3FF)
{
Val.DataHi = 0x3FF;
}
}
else
{
// set middle of range
Val.DataHi = 0x200;
}
}
else
{
// Disabe output stream after emptying the buffer
SempEna = FALSE;
SempPerCurrHold = SempPeriod;
pSpkData = AudioSpkData;
}
}
else
{
SempPerCurrHold = SempPeriod;
}
if(MicEna)
{
if(!AudioFeat2Mute && AudioMicVolMul)
{
// Get ADC sample and remove offset
MicTemp.Data = AD0GDR_bit.RESULT - 0x200;
// Start conversion
AD0CR_bit.START = 1;
// Add volume
MicTemp.Data *= AudioMicVolMul;
// check for overflow and correct the result
if(MicTemp.DataHi < -511)
{
MicTemp.Data = -511 * 65536;
}
else if(MicTemp.DataHi > 511)
{
MicTemp.Data = 511 * 65536;
}
// Scale to 16bit
MicTemp.Data <<= 6;
}
else
{
// set middle of range
MicTemp.DataHi = 0;
}
// write to output buffer
*pMicData++ = MicTemp.DataHi;
}
T0MR0 = SempPerCurrHold;
T0IR = T0IR;
}
/*************************************************************************
* Function Name: AudioFeatureGetReg
* Parameters: Int32U CS, Int32U Id
*
* Return: Boolean
*
* Description:
*
*************************************************************************/
static Boolean AudioFeatureGetReg (Int32U CS, Int32U Id)
{
switch (CS)
{
case REQUEST_GET_CUR:
// Load current value of Volume in the transmit buffer
if (Id == FeatUnit1Id)
{
AudioBuf[1] = (AudioFeat1Vol>>8)& 0xFF;
AudioBuf[0] = AudioFeat1Vol & 0xFF;
}
else if (Id == FeatUnit2Id)
{
AudioBuf[1] = (AudioFeat2Vol>>8)& 0xFF;
AudioBuf[0] = AudioFeat2Vol & 0xFF;
}
else
{
return(FALSE);
}
break;
case REQUEST_GET_MIN:
// Load minimum value of Volume in the transmit buffer
if (Id == FeatUnit1Id)
{
AudioBuf[1] = (Feat1MinVol>>8) & 0xFF;
AudioBuf[0] = Feat1MinVol & 0xFF;
}
else if (Id == FeatUnit2Id)
{
AudioBuf[1] = (Feat2MinVol>>8) & 0xFF;
AudioBuf[0] = Feat2MinVol & 0xFF;
}
else
{
return(FALSE);
}
break;
case REQUEST_GET_MAX:
// Load maximum value of Volume in the transmit buffer
if (Id == FeatUnit1Id)
{
AudioBuf[1] = (Feat1MaxVol>>8) & 0xFF;
AudioBuf[0] = Feat1MaxVol & 0xFF;
}
else if (Id == FeatUnit2Id)
{
AudioBuf[1] = (Feat2MaxVol>>8) & 0xFF;
AudioBuf[0] = Feat2MaxVol & 0xFF;
}
else
{
return(FALSE);
}
break;
case REQUEST_GET_RES:
// Load resolution value of Volume in the transmit buffer
if (Id == FeatUnit1Id)
{
AudioBuf[1] = (Feat1ResVol>>8) & 0xFF;
AudioBuf[0] = Feat1ResVol & 0xFF;
}
else if (Id == FeatUnit2Id)
{
AudioBuf[1] = (Feat2ResVol>>8) & 0xFF;
AudioBuf[0] = Feat2ResVol & 0xFF;
}
else
{
return(FALSE);
}
break;
default:
return(FALSE);
}
return(TRUE);
}
/*************************************************************************
* Function Name: UsbClassAudioRequest
* Parameters: void * pArg
*
* Return: void *
*
* Description: USB Class Audio Requests
*
*************************************************************************/
void * UsbClassAudioRequest (void * pArg)
{
UsbEpCtrl_t * pAdioReqCtrl = (UsbEpCtrl_t *) pArg;
UsbSetupPacket_t * pAudioReqPacket = (UsbSetupPacket_t *)pAdioReqCtrl->pData;
// Validate Request
switch (pAudioReqPacket->mRequestType.Recipient)
{
case UsbRecipientInterface:
// Feature Unit requests only imlement for interface 0
if ((pAudioReqPacket->wIndex.Word == (FeatUnit1Id << 8)) ||
(pAudioReqPacket->wIndex.Word == (FeatUnit2Id << 8)))
{
// Requset type
switch (pAudioReqPacket->wValue.Hi)
{
case FU_MUTE_CONTROL:
if ((pAudioReqPacket->bRequest == REQUEST_SET_CUR) &&
(pAudioReqPacket->wLength.Word == 1))
{
// Set mute flag
AudioRequest = pAudioReqPacket->bRequest;
AudioId = pAudioReqPacket->wIndex.Hi;
AudioCS = pAudioReqPacket->wValue.Hi;
AudioCN = pAudioReqPacket->wValue.Lo;
AudioDataSize = pAudioReqPacket->wLength.Word;
pAdioReqCtrl->Counter= 1;
pAdioReqCtrl->pData = AudioBuf;
return((void *)UsbUserReceivePacket);
}
else if ((pAudioReqPacket->bRequest == REQUEST_GET_CUR) &&
(pAudioReqPacket->wLength.Word == 1))
{
// Read mute flag
if(pAudioReqPacket->wIndex.Hi == FeatUnit1Id)
{
AudioBuf[0] = AudioFeat1Mute;
}
else
{
AudioBuf[0] = AudioFeat2Mute;
}
pAdioReqCtrl->Counter= 1;
pAdioReqCtrl->pData = AudioBuf;
return((void*)UsbUserSendPacket);
}
break;
case FU_VOLUME_CONTROL:
if(pAudioReqPacket->bRequest & 0x80)
{
// Read differnt volume valules
if((pAudioReqPacket->wLength.Word == 2) &&
AudioFeatureGetReg(pAudioReqPacket->bRequest,pAudioReqPacket->wIndex.Hi))
{
pAdioReqCtrl->Counter = 2;
pAdioReqCtrl->pData = AudioBuf;
return((void*)UsbUserSendPacket);
}
}
else if((pAudioReqPacket->bRequest == REQUEST_SET_CUR) &&
(pAudioReqPacket->wLength.Word == 2))
{
// Set volume valule
AudioRequest = pAudioReqPacket->bRequest;
AudioId = pAudioReqPacket->wIndex.Hi;
AudioCS = pAudioReqPacket->wValue.Hi;
AudioCN = pAudioReqPacket->wValue.Lo;
AudioDataSize = pAudioReqPacket->wLength.Word;
pAdioReqCtrl->Counter = 2;
pAdioReqCtrl->pData = AudioBuf;
return((void *)UsbUserReceivePacket);
}
break;
}
}
// Selector Unit requests only imlement for interface 0
else if (pAudioReqPacket->wIndex.Word == (SelUnit1ID << 8))
{
if(pAudioReqPacket->wValue.Word == 0)
{
// Read different selector unit values
if(pAudioReqPacket->bRequest & 0x80)
{
if(pAudioReqPacket->wLength.Word == 1)
{
AudioBuf[0] = 1;
pAdioReqCtrl->Counter = 1;
pAdioReqCtrl->pData = AudioBuf;
return((void*)UsbUserSendPacket);
}
}
else
{
// Set channel
AudioRequest = pAudioReqPacket->bRequest;
AudioId = pAudioReqPacket->wIndex.Hi;
AudioDataSize = pAudioReqPacket->wLength.Word;
pAdioReqCtrl->Counter = 1;
pAdioReqCtrl->pData = AudioBuf;
return((void *)UsbUserReceivePacket);
}
}
}
return((void *)UsbUserStallCtrlEp);
case UsbRecipientEndpoint:
return((void *)UsbUserStallCtrlEp);
}
return((void *)UsbUserStallCtrlEp);
}
/*************************************************************************
* Function Name: UsbClassAudioData
* Parameters: void * pArg
*
* Return: void *
*
* Description: USB Class Audio Data receive
*
*************************************************************************/
void * UsbClassAudioData (void * pArg)
{
if((AudioId == FeatUnit1Id) ||
(AudioId == FeatUnit2Id))
{
switch (AudioCS)
{
case FU_MUTE_CONTROL:
// Set mute flag
if (AudioId == FeatUnit1Id)
{
AudioFeat1Mute = AudioBuf[0];
}
else if (AudioId == FeatUnit2Id)
{
AudioFeat2Mute = AudioBuf[0];
}
else
{
return((void*)UsbUserStallCtrlEp);
}
break;
case FU_VOLUME_CONTROL:
// Set volume value
if (AudioId == FeatUnit1Id)
{
AudioFeat1Vol = AudioBuf[0] + ((Int16U)AudioBuf[1]<<8);
if((Int16U)AudioFeat1Vol == MinVol)
{
AudioSpkVolMul = 0;
}
else
{
if (AudioFeat1Vol < (Int16S)Feat1MinVol)
{
AudioFeat1Vol = Feat1MinVol;
}
else if(AudioFeat1Vol > (Int16S)Feat1MaxVol)
{
AudioFeat1Vol = Feat1MaxVol;
}
// -48dB - +6dB multiply
AudioSpkVolMul = (VolumeMul[((AudioFeat1Vol>>8)+0x30) & 0x3F]) >> 6;
}
}
else if (AudioId == FeatUnit2Id)
{
AudioFeat2Vol = AudioBuf[0] + ((Int16U)AudioBuf[1]<<8);
if((Int16U)AudioFeat2Vol == MinVol)
{
AudioMicVolMul = 0;
}
else
{
if (AudioFeat2Vol < (Int16S)Feat2MinVol)
{
AudioFeat2Vol = Feat2MinVol;
}
else if(AudioFeat2Vol > (Int16S)Feat2MaxVol)
{
AudioFeat2Vol = Feat2MaxVol;
}
// -48dB - +6dB multiply
AudioMicVolMul = VolumeMul[((AudioFeat2Vol>>8)+0x30) & 0x3F];
}
}
else
{
return((void*)UsbUserStallCtrlEp);
}
break;
default:
return((void*)UsbUserStallCtrlEp);
}
}
else if (AudioId == SelUnit1ID)
{
// empty
}
else
{
return((void*)UsbUserStallCtrlEp);
}
return((void*)UsbUserSendAckn);
}