技术热线: 4007-888-234

QLdsPIC3]音频编码解码[C30+dsPIC30F6014A]

更新时间: 2019-03-23
阅读量:3014

深圳市英锐恩科技有限公司:台湾麦肯单片机(Micon MDT单片机)亚太地区A级代理商

QLdsPIC3]音频编码解码[C30+dsPIC30F6014A]
//实验功能:熟悉dsPIC芯片的DC1模块功能和音频编解码芯片SI3000的使用
//软件规划:
//          1。音频信号从J10(MIC IN)进去,编码后送dsPIC控制器,dsPIC接收直接送回SI3000解码从J11(SPK OUT)输出
//          2。DCI采用中断接收数据
//          3。SI3000工作在SLAVE从模式(由dsPIC提供SCK)
//硬件规划:
//          1。拨码开关S10全部置ON
//          2。跳线J9全部跳到SLAVE边
//          3。音频输入接到J10(MIC IN)
//          4。音频输出接到J11(SPK OUT)

#include             //dsPIC30F6014标准头文件
  _FOSC(0x0ffe5);                 //4倍频晶振,Failsafe 时钟关闭
  _FWDT(WDT_OFF);                 //关闭看门狗定时器
  _FBORPOR(PBOR_OFF & MCLR_EN);   //掉电复位禁止,MCLR复位使能。
  _FGS(CODE_PROT_OFF);            //代码保护禁止


#define SAMPLE_RATE    7200L
#define FRAMECLKRATE  (SAMPLE_RATE*256L)   //SCK频率使用1.8432M
#define CLOCK_FREQ  (1L*10000000L)   // 采用 4x PLL..PIC 指令频率 (Fosc*4/4)


#define CMD_STAGE0 0 //正常模式
#define CMD_STAGE1 1 //设置lsb告诉解码器下一个控制字是命令
#define CMD_STAGE2 2 //把带命令的字节放到输出缓冲
#define CMD_STAGE3 3 //设置帧模式
#define CMD_STAGE4 4 //回复正常帧模式

#define PROC_BLOCK_SIZE 144 //数据处理块大小
#define QUEUE_SIZE (PROC_BLOCK_SIZE*2) //Rx和Tx队列的大小,必须为处理缓冲大小的2倍

unsigned int* pActiveRxBuf;
unsigned int* pActiveTxBuf;

unsigned char  __attribute__((address(0x900))) CmdStage;
static volatile unsigned int CodecCmd;
static volatile char ClkAdjTrig;

static int TxQue[QUEUE_SIZE];
static int RxQue[QUEUE_SIZE];
static volatile unsigned int TxQTail;
static volatile unsigned int RxQHead;


void InitCodec(void);
void WriteCodecCtrl( unsigned char adr, unsigned char parm );
void AdjustClock( char shift );
unsigned char ReadCodecCtrl( unsigned char adr );

//***************延时程序***************************
void TimeDelay(unsigned char x)
{
 unsigned char i;
    for(i=0;i<x;i++);
}


//************把数据放到接收缓冲的子程序************
inline void PutRxQue(int data)
{
 RxQue[RxQHead++] = data;
 if(RxQHead==QUEUE_SIZE) RxQHead = 0;
}

//***********从接收缓冲获取数据的子程序***************
inline int GetTxQue(void)
{
static int tmp;  
    tmp = RxQue[TxQTail++]&0xFFFE;     //接收到数据送回解码输出
 if(TxQTail==QUEUE_SIZE) TxQTail = 0;
 return tmp;
}

//DCI中断服务子程序
void __attribute__((__interrupt__)) _DCIInterrupt(void)
{
int tmp;
 switch( CmdStage )
 {
  case CMD_STAGE0:            
   TXBUF0 = GetTxQue();
    TXBUF1 = GetTxQue();
   TXBUF2 = GetTxQue();
   TXBUF3 = GetTxQue();
   PutRxQue(RXBUF0);
   PutRxQue(RXBUF1);
   PutRxQue(RXBUF2);
   tmp = RXBUF3;   //调整时钟的相位
   if(ClkAdjTrig > 0)  //如果需要插入采样
    PutRxQue(tmp);
   if(ClkAdjTrig >= 0)  //如果不须,则跳过
    PutRxQue(tmp);
   ClkAdjTrig = 0;
   break;
  case CMD_STAGE1:
   TXBUF0 = GetTxQue();
   TXBUF1 = GetTxQue();
   TXBUF2 = GetTxQue();
   TXBUF3 = GetTxQue() | 1; //告诉编码解码器下一个值是命令
   PutRxQue(RXBUF0);
   PutRxQue(RXBUF1);
   PutRxQue(RXBUF2);
   PutRxQue(RXBUF3);
   CmdStage = CMD_STAGE2;
   break;
  case CMD_STAGE2:
   TXBUF0 = CodecCmd;      //插入编码解码器命令
   TXBUF1 = GetTxQue(); //取采样数据
   TXBUF2 = 0x0000;    //写虚拟值
   TXBUF3 = 0x0000;    //写虚拟值
   PutRxQue(RXBUF0);
   PutRxQue(RXBUF1);
   PutRxQue(RXBUF2);
   PutRxQue(RXBUF3);
   CmdStage = CMD_STAGE3;
   break;
  case CMD_STAGE3:
   TXBUF0 = GetTxQue();
   TXBUF1 = GetTxQue();
   TXBUF2 = GetTxQue();
   TXBUF3 = GetTxQue();
   PutRxQue(RXBUF0);
   PutRxQue(RXBUF1);
   PutRxQue(RXBUF2);
   PutRxQue(RXBUF3);
   
            DCICON2=0XF6FF;        //设置DCI缓冲长度为2
   CmdStage = CMD_STAGE4;
   break;
  case CMD_STAGE4:
   TXBUF0 = GetTxQue();
   TXBUF1 = GetTxQue();
   TXBUF2 = GetTxQue();
   TXBUF3 = GetTxQue();
   CodecCmd = RXBUF0;
   PutRxQue(RXBUF1);
   
            DCICON2=0XFFFF;      //设置DCI缓冲长度为4
   CmdStage = CMD_STAGE0;
   break;
 }
 IFS2bits.DCIIF = 0; // 清DCI中断标志
}

//**************初始化DCI和编码解码器*******************
void InitCodec(void)
{
int i;
 for(i=0; i {
  RxQue[i] = 0;
  TxQue[i] = 0xffff;
 }
 TxQTail = 0;
 RxQHead = 0;
 CmdStage = CMD_STAGE0;
 CodecCmd = 0;
 ClkAdjTrig = 0;
 TRISFbits.TRISF6 = 1; //编码解码器(Codec)引脚为输入
    IFS2bits.DCIIF = 0;
    IEC2bits.DCIIE=1;
    IPC10bits.DCIIP=7;
 
    DCICON1=0X8040;         // 配置DCI模块用于传送16位数据且工作在多通道模式
    DCICON2=0XFFFF;
    DCICON3=( CLOCK_FREQ / ( 2 * FRAMECLKRATE) ) - 1;
    TSCON=1;
    RSCON=1;
 LATFbits.LATF6 = 0; //复位编码解码器
 TRISFbits.TRISF6 = 0;
 TimeDelay(200);
 TRISFbits.TRISF6 = 1; //编码解码器设为输入
 TimeDelay(1);

 WriteCodecCtrl( 3, 0);  //SI3000寄存器3
 WriteCodecCtrl( 4, 19);     //SI3000寄存器4
    WriteCodecCtrl( 1,0X18 );   //SI3000寄存器1
 WriteCodecCtrl( 2, 0);     //SI3000寄存器2
    WriteCodecCtrl( 5, 2);      //SI3000寄存器5
    WriteCodecCtrl( 6, 0X5E );  //SI3000寄存器6
    WriteCodecCtrl( 7, 0X5F );  //SI3000寄存器7
    WriteCodecCtrl( 9, 0);      //SI3000寄存器9
}

//*************写命令到编码解码器子程序**********************
void WriteCodecCtrl( unsigned char adr, unsigned char parm )
{
 CodecCmd = (unsigned int)adr;
 CodecCmd = (CodecCmd<<8) & 0x1F00;     //SI3000寄存器的5位地址
 CodecCmd += (unsigned int)parm;        //待写入的数据
 CmdStage = CMD_STAGE1;
 while( CmdStage != CMD_STAGE0 ){}
}

//*************从编码解码器读命令子程序**********************
unsigned char ReadCodecCtrl( unsigned char adr )
{
 CodecCmd = (unsigned int)adr;
 CodecCmd = (CodecCmd<<8) & 0x1F00;
 CodecCmd |=  0x2000;                  //读功能
 CmdStage = CMD_STAGE1;
 while( CmdStage != CMD_STAGE0 ){}
 return CodecCmd&0x00FF;
}

//**********************主函数*******************************
int main(void)
{
    TRISG=0X1000;
 InitCodec();
    while(1);
}