有个想法,自己弄个播放器多好玩啊,想了想,应该分为以下几个部分
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;
}
已经大半年了啊