深圳市英銳恩科技有限公司:臺灣麥肯單片機(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);
}