DSP

自己曾经做过的基于DSP的WAV播放器

2019-07-13 12:44发布

有个想法,自己弄个播放器多好玩啊,想了想,应该分为以下几个部分 1.得有个处理器,我有BF592 2.得有个音频解码器,我有SSM2603 3.得有个存储器,我有M25P16 当前的情况是这三个我都有 按照难度,先来存储器,U盘还是SD卡呢?思考下,还是SD好些,理由是因为DSP支持SPI,而SD可以直接使用SPI,确定了 正好我有手机卡,今天买朗琴X6,送了个卡托,硬件全齐了 然后焊接,图如下,   图片  这个是以前做的,代码还在 第一个是12864的驱动代码 void delay(int delay); void Lcdwrite(char command,char se); void sendbit(char xx); void Init12864(void); /////////////////////////////// void delay(int delay) { int i; for(i=0;i>5; //转移到PF2 tmp=tmp & 0x04; *pPORTFIO &=0xfffb; //清除PF2 ssync(); *pPORTFIO |=tmp; //给数据 ssync(); *pPORTFIO &=0xfffd; //拉低时钟 ssync(); *pPORTFIO |=0x0002; //拉高时钟 ssync(); } } void Init12864(void) { delay(1000); Lcdwrite(0x30,0xf8); Lcdwrite(0x0c,0xf8); Lcdwrite(0x01,0xf8); Lcdwrite(0x06,0xf8); delay(1000); }
这个是手机卡的代码 #define DELAY 300 #define u8 unsigned char #define u16 unsigned int #define u32 unsigned long int fatstart=97; int datastart=7871; unsigned char fat[512]; //用于读取处fat表分析用的 int rootnextcu=2; //记录根目录的下一簇号,默认初始化为2号 unsigned char root[512*8]; //4KB,用以读取根目录内容并分析 void Wait_For_SPI1F(void); //等待函数 void SetupSPI1( const int spi_setting ); //初始化SPI1; void ReadByte(unsigned char *pusValue ); //传感器的单字节读取函数 void WriteByte(unsigned char usValue ); //传感器的单字节写函数 u8 SendCmd(u8 cmd,u32 arg,u8 last); int speedsd; int GetSec(int cuhao); //根据簇号返回扇区 int GetNextCuhao(int cuhao); //根据簇号返回下一个簇号 int GetCu(int position); //根据传入的指针从根目录的目录项中获取簇号 /****************************************************/ //发送卡命令 /**************************************/ u8 SendCmd(u8 cmd,u32 arg,u8 last) { unsigned char i=0xff; int tmp=0; WriteByte(0xff); WriteByte(cmd | 0x40); WriteByte(arg>>24); WriteByte(arg>>16); WriteByte(arg>>8); WriteByte(arg); WriteByte(last); while(tmp<100) { ReadByte(&i); if(i!=0xff) break; tmp++; } return i; } void ReadByte(unsigned char *pusValue ) { // disable interrupts before performing the load or store operation *pusValue = *pSPI1_RDBR; Wait_For_SPI1F(); *pSPI1_TDBR = 0xff; Wait_For_SPI1F(); *pusValue = *pSPI1_RDBR; } /********************************************/ /**********************************************/ void WriteByte(unsigned char usValue ) { *pSPI1_TDBR = usValue; Wait_For_SPI1F(); } /*********************************************/ /*********************************************/ void Wait_For_SPI1F(void) { volatile int n; for(n=0; n
这个也是SD卡的代码,是块读取的
#define DELAY 300 #define u8 unsigned char #define u16 unsigned int #define u32 unsigned long int fatstart=97; int datastart=7871; unsigned char fat[512]; //用于读取处fat表分析用的 int rootnextcu=2; //记录根目录的下一簇号,默认初始化为2号 unsigned char root[512*8]; //4KB,用以读取根目录内容并分析 void Wait_For_SPI1F(void); //等待函数 void SetupSPI1( const int spi_setting ); //初始化SPI1; void ReadByte(unsigned char *pusValue ); //传感器的单字节读取函数 void WriteByte(unsigned char usValue ); //传感器的单字节写函数 u8 SendCmd(u8 cmd,u32 arg,u8 last); int speedsd; int GetSec(int cuhao); //根据簇号返回扇区 int GetNextCuhao(int cuhao); //根据簇号返回下一个簇号 int GetCu(int position); //根据传入的指针从根目录的目录项中获取簇号 /****************************************************/ //发送卡命令 /**************************************/ u8 SendCmd(u8 cmd,u32 arg,u8 last) { unsigned char i=0xff; int tmp=0; WriteByte(0xff); WriteByte(cmd | 0x40); WriteByte(arg>>24); WriteByte(arg>>16); WriteByte(arg>>8); WriteByte(arg); WriteByte(last); while(tmp<100) { ReadByte(&i); if(i!=0xff) break; tmp++; } return i; } void ReadByte(unsigned char *pusValue ) { // disable interrupts before performing the load or store operation *pusValue = *pSPI1_RDBR; Wait_For_SPI1F(); *pSPI1_TDBR = 0xff; Wait_For_SPI1F(); *pusValue = *pSPI1_RDBR; } /********************************************/ /**********************************************/ void WriteByte(unsigned char usValue ) { *pSPI1_TDBR = usValue; Wait_For_SPI1F(); } /*********************************************/ /*********************************************/ void Wait_For_SPI1F(void) { volatile int n; for(n=0; n
这个是SSM2603的代码 int initSSM2603(void); void TWI_MasterMode_Write(unsigned short DeviceAddr, unsigned char *TWI_Data_Pointer, unsigned short Count, unsigned short TWI_Length); void Init_Sport0_Audio(bool tx, bool rx); void Init_DMA_Audio(bool tx, bool rx); void Enable_DMA_Sport0_Audio(bool tx, bool rx); void Init_Flags_Audio(void); #define SLEN_16 0x000f #define FLOW_1 0x0000 //////////////////////////////////// //初始化SSM2603 //////////////////////////////////// int initSSM2603(void) { int i; *pTWI_FIFO_CTL |= XMTFLUSH; // Clear the TX FIFO *pTWI_MASTER_STAT = BUFWRERR | BUFRDERR | DNAK | ANAK | LOSTARB; // Clear all status error ssync(); delay(100000); unsigned char ResetControl[] = { 0x1e, 0x00}; unsigned char LeftLineIn[] = { 0x00, 0x01b}; unsigned char RightLineIn[] = { 0x02, 0x01b}; unsigned char LeftHpOut[] = { 0x04, 0x05a}; unsigned char RightHpOut[] = { 0x06, 0x05a}; unsigned char AnalogControl[] = { 0x08, 0x010}; unsigned char DigitalControl[] = { 0x0a, 0x000}; unsigned char PowerDownControl[] = { 0x0c, 0x000}; unsigned char DigitalAudioFormat[] ={ 0x0e, 0x042}; unsigned char SamplingControl[] = { 0x10, 0x023}; unsigned char ActiveControl[] = { 0x12, 0x001}; TWI_MasterMode_Write( 0, ResetControl, 1, 2); //初始化所有内容 TWI_MasterMode_Write( 0, LeftLineIn, 1, 2); TWI_MasterMode_Write( 0, RightLineIn, 1, 2); TWI_MasterMode_Write( 0, LeftHpOut, 1, 2); // TWI_MasterMode_Write( 0, RightHpOut, 1, 2); //左右耳机 TWI_MasterMode_Write( 0, AnalogControl, 1, 2); TWI_MasterMode_Write( 0, DigitalControl, 1, 2); //设置数字音频路径 TWI_MasterMode_Write( 0, PowerDownControl, 1, 2); //全部上电 TWI_MasterMode_Write( 0, DigitalAudioFormat, 1, 2); TWI_MasterMode_Write( 0, SamplingControl, 1, 2); //采样频率 delay(100000); TWI_MasterMode_Write( 0, ActiveControl, 1, 2); //激活数字内核 return 1; } ////////////////////////////////////////////// ///向SSM2603写指令 ////////////////////////////////////////////// void TWI_MasterMode_Write(unsigned short DeviceAddr, unsigned char *TWI_Data_Pointer, unsigned short Count, unsigned short TWI_Length) { int i, j, timeout; *pTWI_FIFO_CTL = 0; *pTWI_CONTROL = TWI_ENA | 7; *pTWI_CLKDIV = CLKLOW(50) | CLKHI(50); *pTWI_MASTER_ADDR = 0x1b; /* target address (7-bits plus the read/write bit) */ for (i = 0; i < Count; i++) { /* # of configurations to send */ *pTWI_XMT_DATA8 = *TWI_Data_Pointer++; /* pointer to data */ ssync(); *pTWI_MASTER_CTL = (TWI_Length<<6) | MEN /*| FAST*/; /* start transmission */ timeout = 0x1000; // TAR37913 for (j = 0; j < (TWI_Length-1); j++) { /* # of transfers before stop condition */ while ((*pTWI_FIFO_STAT == XMTSTAT) && --timeout) /* wait to load the next sample into the TX FIFO */ // TAR37913 { asm("nop;"); // TAR37913 asm("nop;"); asm("nop;"); ssync(); } if(!timeout) // TAR37913 return; *pTWI_XMT_DATA8 = *TWI_Data_Pointer++; /* load the next sample into the TX FIFO */ ssync(); } while ((*pTWI_INT_STAT & MCOMP) == 0) /* wait until transmission complete and MCOMP is set */ ssync(); *pTWI_INT_STAT = XMTSERV | MCOMP; /* service TWI for next transmission */ } asm("nop;"); asm("nop;"); asm("nop;"); } //////////////////////////////////////////////////////////// /**************************************************************************** * Function: Init_Sport0_Audio * Description: Configure SPORT0 for I2S mode, to transmit/receive data * to/from the codec. Configure Sport for ext clock and * internal frame sync. ******************************************************************************/ void Init_Sport0_Audio(bool tx, bool rx) { if ( rx ) { /* sport0 receive configuration */ *pSPORT0_RCR1 = RFSR | RCKFE; *pSPORT0_RCR2 = SLEN_16 | RSFSE; } if ( tx ) { /* sport0 transmit configuration */ *pSPORT0_TCR1 = TFSR | TCKFE; *pSPORT0_TCR2 = SLEN_16 | TSFSE; } } /**************************************************************************** * Function: Init_DMA_Audio * Description: DMA Controller Programming For SPORT0 * Sets up DMA1 and DMA2 in autobuffer mode to receive and * transmit SPORT data ******************************************************************************/ void Init_DMA_Audio(bool tx, bool rx) { if ( rx ) { /* configure DMA1 */ /* 32-bit transfers, interrupt on completion, autobuffer mode */ *pDMA1_CONFIG = WNR | WDSIZE_16 | DI_EN | FLOW_1; *pDMA1_X_COUNT = 4; /* DMA loop count */ *pDMA1_X_MODIFY = 2; /* DMA loop address increment */ } if ( tx ) { /* configure DMA2 */ *pDMA2_CONFIG = WDSIZE_16 | FLOW_1 ; /* 16-bit transfers, autobuffer mode */ *pDMA2_START_ADDR = g_sInput_DMA; /* start address of data buffer */ *pDMA2_X_COUNT = (8 * 256); //每次传输的是16位,一个扇区传输的是256次 *pDMA2_X_MODIFY = 2; /* DMA loop address increment */ } } /**************************************************************************** * Function: Enable_DMA_Sport0_Audio * Description: Enable DMA1, DMA2, Sport0 TX and Sport0 RX ******************************************************************************/ void Enable_DMA_Sport0_Audio(bool tx, bool rx) { if ( rx ) { *pDMA1_CONFIG = (*pDMA1_CONFIG | DMAEN); /* enable DMA for RX */ *pSPORT0_RCR1 = (*pSPORT0_RCR1 | RSPEN); /* enable sport0 RX */ } if ( tx ) { *pDMA2_CONFIG = (*pDMA2_CONFIG | DMAEN); /* enable DMA for TX */ *pSPORT0_TCR1 = (*pSPORT0_TCR1 | TSPEN); /* enable sport0 TX */ } } /**************************************************************************** * Function: Init_Flags_Audio * Description: Configure PORTG and PORTH flags to control CODEC ******************************************************************************/ void Init_Flags_Audio(void) { /* DT0PRI, DR0PRI, RFS0, RSCLK0, TFS0, TSCLK0 */ *pPORTG_MUX &= ~(PG1 | PG2 | PG3 | PG5 | PG6 | PG7); ssync(); *pPORTG_FER |= (PG1 | PG2 | PG3 | PG5 | PG6 | PG7); ssync(); } //////////////////////////////////////////////////////////////////////////////
这个是主代码 #include #include #include #include #include #include unsigned char g_sInput_DMA[512*8]; unsigned char g_sInput_DMA1[512*8]; #include "12864.c" #include "sd.h" #include "sdcon.c" #include "sdfunction.c" #include "SSM2603.c" #include "mp3.c" void InitAll(void); int main( void ) { int i,j,sec,flag; sec=7879; flag=0; InitAll(); FindWav(); //读取根目录内容,并查找WAV文件并播放 while(sec<89272) { if(flag==0) { *pDMA2_START_ADDR=g_sInput_DMA; *pDMA2_CONFIG = (*pDMA2_CONFIG | DMAEN); for(i=0;i<15;i++) { while( SDReadBlock(sec,&g_sInput_DMA1[i*512])!=0) ; sec++; } } else { *pDMA2_START_ADDR=g_sInput_DMA1; *pDMA2_CONFIG = (*pDMA2_CONFIG | DMAEN); for(i=0;i<15;i++) { while(SDReadBlock(sec,&g_sInput_DMA[i*512])!=0) ; sec++; } } while(1) { if(*pDMA2_IRQ_STATUS==0) { break; } } flag =~flag; if(sec>89255) { sec=7879; } } return 0; } void InitAll(void) { delay(10000); initSSM2603(); initSD(); Init_Flags_Audio(); //改变GPIO的功能 Init_Sport0_Audio(true, true); //初始化SPROT0 Init_DMA_Audio(true, true); Enable_DMA_Sport0_Audio(true, true); delay(100000); }
这个是播放代码
int PlayWav(int position); //传递进一个0-512*8的指针,即有效的目录项位置,然后从ROOTDATA中找到目录项并播放 void FindWav(void); //读取根目录内容,并查找WAV文件并播放 int FindNextWav(int position); //传递进一个0-512*8的指针,为16的整数倍,返回WAV簇号,返回-1,说明已经到头了 int SetAudio(void); //根据文件内容设置传输,如每次传输的字节,采样频率等信息,返回-1说明不是有效的WAV文件 //////////*/////////////////////////////// void FindWav(void) { int tmp0,tmp1,i; while(1) { //程序无限循环播放 tmp0=GetSec(rootnextcu); //根据簇号获取到扇区号 for(i=0;i<8;i++,tmp0++) { while( SDReadBlock(tmp0,&root[i*512])!=0) ; } //读出一个簇 rootnextcu=GetNextCuhao(rootnextcu); //更新下一个簇号 if(rootnextcu==0x0fffffff) rootnextcu=2; //无限循环 tmp0=0; //每次读取一个新的根目录数据时,指针都清零 while(1) { tmp0=FindNextWav(tmp0); if(tmp0!=-1) { //有效的WAV文件 PlayWav(tmp0); //播放Wav文件 tmp0 +=0x20; //增加指针,指向下一个目录项 } else { break; //该簇内没有音乐,查找下一个簇 } } } } ///////////////////////////////////////////// int FindNextWav(int position) { int tmp0,i; unsigned char wavv[3]={"WAV"}; while(position<512*8) { ///在一个簇内 if(root[position]==0x00 || root[position]==0xe5) { position +=0x20; continue; } //如果是未分配项或者是删除项那么跳过,进入下一个项 else { for(i=0;i<3;i++) { if(root[position+8+i]!=wavv[i]) { break; } } if(i!=3) { position +=0x20; continue; } else { return position; } } } return -1; } ///////////////////////////////////////////////////////// int PlayWav(int position) { int cuhao,i,j,flag,nextcu,sec; cuhao=GetCu(position); //获取该目录项中文件的第一个簇号 nextcu=GetNextCuhao(cuhao); //获取文件的下一个簇号 sec=GetSec(cuhao); //根据当前簇号获取扇区号 for(i=0;i<8;i++,sec++) { while( SDReadBlock(sec,&g_sInput_DMA[i*512])!=0) ; } //读出一个簇 flag=SetAudio(); if(flag==-1) { return 1; } flag=0; //初始化标志 while(nextcu!=0x0fffffff) { //文件未结束 if(flag==0) { *pDMA2_START_ADDR=g_sInput_DMA; *pDMA2_CONFIG = (*pDMA2_CONFIG | DMAEN); cuhao=nextcu; nextcu=GetNextCuhao(cuhao); sec=GetSec(cuhao); for(i=0;i<8;i++) { while( SDReadBlock(sec,&g_sInput_DMA1[i*512])!=0) ; sec++; } } else { *pDMA2_START_ADDR=g_sInput_DMA1; *pDMA2_CONFIG = (*pDMA2_CONFIG | DMAEN); cuhao=nextcu; nextcu=GetNextCuhao(cuhao); sec=GetSec(cuhao); for(i=0;i<8;i++) { while(SDReadBlock(sec,&g_sInput_DMA[i*512])!=0) ; sec++; } } while(1) { if(*pDMA2_IRQ_STATUS==0) { break; } } flag =~flag; } return 0; } //////////////////////////////////////////////////////////// int SetAudio(void) //设定传输,并返回声道数 { //从g_sInput_DMA中获取文件信息并设置音频解码器和SPORT0以及DMA2 int i,j,k; int channels,samplesPerSec,BitsPerSample;//声道数,采样频率,每个采样需要的bit数 unsigned char riff[4]={"RIFF"}; unsigned char wave[4]={"WAVE"}; for(i=0;i<4;i++) { //文件信息存在于g_sInput_DMA中 if(g_sInput_DMA[i]!=riff[i] || g_sInput_DMA[8+i]!=wave[i]) { return -1; } } channels=g_sInput_DMA[0x16]; //获取声道数 samplesPerSec=(g_sInput_DMA[0x19]<<8)+g_sInput_DMA[0x18]; //获取采样频率 BitsPerSample=g_sInput_DMA[0x22]; if(channels==1) { return -1; } if(BitsPerSample!=0x10) { return -1; } if(samplesPerSec!=0xac44) { return -1; } return 0; }
已经大半年了啊