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); 
}