【原创】SD卡WAV音乐播放器(quartus11.0)(FAT32)(DE2-115)

  准备工具:格式工厂,Windows录音机,SD卡(小于等于2G),音箱

  首先,选一首MP3,用格式工场转化成WAV格式。可以看到转化后的文件变得很大,因为WAV就是AD采样值加个文件头,所以数据量巨大,这也是MP3压缩算法流行的原因。

  将转化后的WAV文件用Windows录音机打开编辑,采样率设置为8Khz,16位立体声,然后写入到SD卡里,恩,这里提一句,可以写入任意数量的歌曲,我写的程序是播放完卡里所有的WAV文件。当然别放其他文件例如图片文件进去捣乱啊,文件系统里没有识别其他文件的过程,开学了,要忙活了就没做。

  硬件搭建:

  SD卡的部分就不说了,前面博客提过了。说说WM8731吧,我们管这个芯片叫霸气闪耀,因为它里面有24位的ADC和DAC,而且是CD音质,听起来感觉不错的。驱动芯片首先当然是看手册,50多页的手册,还凑合。我们关心的只有几个部分:DAC,控制接口,数据接口。先来看看它的框图:

由于我们是将SD卡里的数字数据读出来,写入DAC,所以我们不管ADC的部分,注意这三个红圈,上面的红圈是控制接口,是用户控制8731工作模式写命令的接口,接口采用I2C协议;右边的红圈是耳机输出,默认是静音,坑爹啊,这个设置一样要改,不然没声的。下面的红圈是数据接口,我们的数据数据从这里串行输入。好,明确了这些概念后,我们来看8731的控制寄存器。如下图:

8731一共11个寄存器,保守起见,每个都设置一遍最好。这里还有个坑爹的地方,开始看手册不细,被耍的够惨。这个复位寄存器,当我们写入复位命令后,8731就将所有的控制寄存器先写入0.本来一上电,8731会自己复位,并且自动配置寄存器的值,但是这个软件复位的效果和上电复位的不一样,上电复位后控制寄存器里的值不是0,而是一些默认的设置,软件复位后,所有的都是零了。

  扯一扯I2C协议

  I2C协议点对点传输还是比较简单的,不用考虑仲裁等乱七八糟的事。8731的I2C协议如下图所示:

注意8731的设备号是可变的,而DE2-115上已经将其固定为0X34了,最后一位是读写选择,8731是只写的,不能读,所以地址加上R/W位就是0X34。发送完8位设备地址加读写位后,接下来发送16位数据,前7位是8731内部寄存器的地址,后9位是寄存器配置的数据。每一个命令封装成24位的一帧,每次发送命令都要完整的发送:起始标志,设备号,读写位,7位寄存器地址,9位数据。

  命令接口说完了,接下来是数据接口,这个有些麻烦。我们要写入串行的数据,就要自己写并转串的接口。数据写入有四种模式:左对齐,I2S,和右对齐,DSP模式。继续看手册:

左对齐模式,也是我采用的模式,数据在DACLRCK的下降沿后BCLK的第一个上升沿就有效。

I2S模式,数据会延迟一个BCLK才有效。

右对齐模式,就是数据最高位和DACLRCK的下降沿对齐。

不在以DACLRCK的高低电平来区分左右声道了。数据时连续的。

我们采用左对齐方式,用硬件去实现高速的并转串接口。在检测到DACLRCK的下降沿或者上升沿后,使能模16计数器,当计数器计满时,使计数使能无效。在计数过程中,将并行数据移位输出到DACDAT引脚上。模块代码如下:

/*
*this file is use to connect the dule port ram and 8731
*when the up edge of lrck,read from the ram,and when the down edge of lrck,increace the ram address
*when the up edge of bclk,shift the 64 regs,and the msb is out to the 8731 dacda pin
*/
module data_64
(
input clk,
input rst_n,
input [31:0]q,
input bclk,
input lrck,
output q_out,
output rd_en,
output [16:0]ram_addr
);

//**************************************************************************************************
//up and down edge of lrck detect module
reg latch0;
reg latch1;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
latch0
<=1'b0;
latch1<=1'b0;
end
else
begin
latch0
<=lrck;
latch1
<=latch0;
end
end
wire up_detect;
wire down_detect;
assign up_detect=latch0 && (~latch1);
assign rd_en=up_detect;
assign down_detect=latch1 && (~latch0);

//****************************************************************************************************************
//up and down edge of bclk detect module
reg latch2;
reg latch3;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
latch2
<=1'b0;
latch3<=1'b0;
end
else
begin
latch2
<=bclk;
latch3
<=latch2;
end
end
wire up;
wire down;
assign up=latch2 && (~latch3);
assign down=latch3 && (~latch2);


//************************************************************************************************************
//latch up_detect module,delay the up_detect for one clk for the data read from ram
reg write;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
write
<=1'b0;
else
write
<=up_detect;
end

//*************************************************************************************************************
//64 reg module
reg[31:0]data;
wire[23:0]gnd;
wire shift;
assign gnd=24'b0;
assign shift=1'b0;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
data
<=32'b0;
else if(write)
data
<=q[31:0];
else if(up && en)
data
<={data[30:0],shift};
end
assign q_out=data[31];

//************************************************************************************************************
//ram addr generater
reg[16:0]addr;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
addr
<=17'b0;
else if((addr==17'b11111_1111_1111_1111) && (down_detect ||up_detect))
addr<=15'b0;
else if(down_detect ||up_detect)
addr
<=addr+1'b1;
end
assign ram_addr=addr;

//************************************************************************************************************
//counter enable module
reg en;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
en
<=1'b0;
else if(cnt_over)
en
<=1'b0;
else if(up_detect || down_detect)
en
<=1'b1;
end
//*************************************************************************************************************
//16 bits counter,count the BCLK posedge
reg[7:0]cnt;
wire cnt_over;
wire not_over;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt
<=8'b0;
// cnt_over<=1'b0;
end
else if((cnt==8'd16) && en )
begin
cnt
<=8'b0;
// cnt_over<=1'b1;
end
else if(en && up)
begin
cnt
<=cnt+1'b1;
// cnt_over<=1'b0;
end
end
assign cnt_over=(cnt==8'd16)?1'b1:1'b0;
assign not_over=~cnt_over;

endmodule

  本来这个模块式用来从ram里读数据的,后来发现ram只能缓存很小的数据,就改用FIFO了,但是地址线没有去掉。

  建立一个FIFO来缓冲数据,数据位宽为32位,1024*32bit大小,其实用256*32bit也可以的。利用FIFO里面的WRUSEW的最高位(就是FIFO一半满时的标记),来决定是否写入数据。如图:

写请求是软件发出的,宽度不确定,那么我们写一个模块来检测它的上升沿,在上升沿出现时,产生一个clk宽度的信号,来向fifo写入数据。clk为100M。

module wr_req_detect
(
input clk,
input rst_n,
input wr_req,
output wr_req_detect
);
reg latch0;
reg latch1;
reg latch2;
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
latch0
<=1'b0;
latch1<=1'b0;
latch2<=1'b0;
end
else
begin
latch0
<=wr_req;
latch1
<=latch0;
latch2
<=latch1;
end
end
assign wr_req_detect=latch0 && (~latch1);
endmodule

  如果是assign wr_req_detect=latch0 && (~latch2);那么就是产生了2个clk宽度的写请求信号,具体原理不讲了,自己体会吧。

  NIOS系统的搭建就是在SD卡系统的基础上多了几个PIO,分别是I2C的两条线,还有FIFO的数据线和写请求线。注意一个问题,FIFO的读写时钟全部同步到系统时钟,即用全局时钟来控制全局,利用使能时钟解决跨时钟域问题,用一个100M的时钟去检测几M的时钟的上升下降沿自然是没有问题的。

  硬件就这么多可说的。

  软件部分,FAT32文件系统,读取WAV跟读取BMP没有什么区别,只是后缀名不同而已,注意文件名不要搞太长,控制在8个字节内。直接贴代码了,我C语言是自学的,写的很菜,因为当时学汇编学的太狠了,导致写出来的C程序跟汇编一个味道,冗长,但是易懂,一看就明白。

  头文件:

/*
* sopc.h
*
* Created on: 2011-8-10
* Author: Fu-xiaoliang
*/

#ifndef SOPC_H_
#define SOPC_H_
#include
"system.h"
#define _LED
typedef
struct
{
unsigned
long int DATA;
unsigned
long int DIRECTION;
unsigned
long int INTERRUPT_MASK;
unsigned
long int EDGE_CAPTURE;
}PIO_STR;
#ifdef _LED
#define SD_DA ((PIO_STR *)SD_DA_BASE)
#define SD_CMD ((PIO_STR *)SD_CMD_BASE)
#define SD_CS ((PIO_STR *)SD_CS_N_BASE)
#define SD_CLK ((PIO_STR *)SD_CLK_BASE)
#define WR_ADDR ((PIO_STR *)WR_ADDR_BASE)
#define WR_CLK ((PIO_STR *)WR_CLK_BASE)
#define WR_DAT ((PIO_STR *)WR_DAT_BASE)
#define WR_EN ((PIO_STR *)WR_EN_BASE)
#define WR_USE_W ((PIO_STR *)WR_USE_W_BASE)
#define RD_EN ((PIO_STR *)RD_EN_BASE)
#define I2C_DAT ((PIO_STR *)I2C_DAT_BASE)
#define I2C_SCLK ((PIO_STR *)I2C_SCLK_BASE)
#define LED ((PIO_STR *)LED_BASE)
#define _SD
#endif

#ifdef _SD
#define data (SD_DA->DATA)
#define cmd (SD_CMD->DATA)
#define cs (SD_CS->DATA)
#define clk (SD_CLK->DATA)
#endif
#define uc unsigned char
#endif /* SOPC_H_ */

  主函数:

/*
 * "Hello World" example.
 *
 * This example prints 'Hello from Nios II' to the STDOUT stream. It runs on
 * the Nios II 'standard', 'full_featured', 'fast', and 'low_cost' example
 * designs. It runs with or without the MicroC/OS-II RTOS and requires a STDOUT
 * device in your system's hardware.
 * The memory footprint of this hosted application is ~69 kbytes by default
 * using the standard reference design.
 *
 * For a reduced footprint version of this template, and an explanation of how
 * to reduce the memory footprint for a given application, see the
 * "small_hello_world" template.
 *
 */

#include <stdio.h>
#include "alt_types.h"  // alt_u32
#include <unistd.h>
#include "sys/alt_irq.h"
#include "D:\FPGA-PROJECT\myself\SD_WAV_DE2\software\DE2_SD_WAV\inc\sopc.h"

//****************************************************************************************************************************
//static variable
uc Resp_buffer[16]={0};
uc data_buffer[512]={0};
uc data_buffer1[512]={0};
unsigned long int FDT_DIRECT[16]={0};
uc not_finish=0;

  unsigned long int DBR_ADDR=0;
  unsigned long int FAT1_ADDR=0;
  unsigned long int FAT2_ADDR=0;
  unsigned long int FDT_ADDR=0;
  unsigned long int CLUS_ADDR=0;
  unsigned long int CLUS_CURRENT=0;//current clus number
  unsigned long int CLUS_LEN=0;//clus lenth
  unsigned long int CLUS_NEXT=0;
  unsigned long int RAM_ADDR=0;

 struct
{
	union
	{
		unsigned char CSD[16];
		unsigned char CSD1[16];
	}CSD_DA;
	union
	{
		unsigned char buf1[16];
		unsigned char buf2[16];

	}CID_DA;
}REG;

struct
{
  uc  RIFF_ID[4];
  unsigned long long int  WAV_SIZE;
  uc  RIFF_TYPE[4];
}WAV_RIFF_CHUNK;

struct
{
   uc FORMAT_ID[4];
   unsigned long long int  FORMAT_SIZE;
   unsigned long int FORMAT_TAG;
   unsigned long int CHANNELS;
   unsigned long long int SAMPLES_PER_SEC;
   unsigned long long int BYTE_PER_SEC;
   unsigned long int BLOCK_ALIGN;
   unsigned long int BITS_PER_SAMPLE;
   unsigned long int ADDITION;
}WAV_FORMAT_CHUNK;

struct
{
  uc FACT_ID[4];
  unsigned long long int FACT_SIZE;
  unsigned long long int FACT_DATA;
}WAV_FACT_CHUNK;

struct
{
  uc DATA_ID[4];
  unsigned long long int DATA_SIZE;

}WAV_DATA_CHUNK;

//*********************************************************************************************************************************************
//function define and statement
uc send_byte(uc sda)
{
	uc cnt=0,rda=0;
	SD_CLK->DATA=1;
	SD_CMD->DIRECTION=1;
	for(cnt=0;cnt<8;cnt++)
	{
		SD_CLK->DATA=0;
		SD_CMD->DATA=0;
		if(sda & 0x80)
			SD_CMD->DATA=1;
		usleep(50);
		sda=sda<<1;
		rda=rda<<1;
		SD_CLK->DATA=1;
		if(SD_DA->DATA)
		{

			rda=rda|0x01;
		}

	}

	SD_CLK->DATA=1;
	return rda;
}
uc send_byte_fast(uc sda)
{
	uc cnt=0,rda=0;
	SD_CLK->DATA=1;
	SD_CMD->DIRECTION=1;
	for(cnt=0;cnt<8;cnt++)
	{
		SD_CLK->DATA=0;
		SD_CMD->DATA=0;
		if(sda & 0x80)
			SD_CMD->DATA=1;
//		usleep(70);
		sda=sda<<1;
		rda=rda<<1;
		SD_CLK->DATA=1;
		if(SD_DA->DATA)
		{

			rda=rda|0x01;
		}
	}
	SD_CLK->DATA=1;
	return rda;
}
uc i2c_send_3byte(uc x,uc y,uc z)
{
	uc i=0;uc a=0;
	I2C_SCLK->DATA=0;
	I2C_DAT->DIRECTION=1;
	I2C_DAT->DATA=1;
	I2C_SCLK->DATA=1;//initial I2C clk and data line
	usleep(10);
	I2C_DAT->DATA=0;//start transfer
	usleep(10);
	I2C_SCLK->DATA=0;
	usleep(10);
	for(i=0;i<8;i++)//send first byte
	{
		usleep(10);
		I2C_DAT->DATA=(x & 0x80)?1:0;
		I2C_SCLK->DATA=1;
		x=x<<1;
		usleep(10);
		I2C_SCLK->DATA=0;
	}
	I2C_DAT->DIRECTION=0;
	I2C_SCLK->DATA=1;
	usleep(10);
	a=I2C_DAT->DATA;
	if(a==0)
	{
		printf("slave replay first byte!\n");
	}
	else
		printf("slave no replay !\n");

	I2C_DAT->DIRECTION=1;
	I2C_SCLK->DATA=0;
	usleep(10);
	for(i=0;i<8;i++)//send second byte
	{
		I2C_DAT->DATA=(y & 0x80)?1:0;
		usleep(10);
		I2C_SCLK->DATA=1;
		y=y<<1;
		usleep(10);
		I2C_SCLK->DATA=0;
	}
	I2C_DAT->DIRECTION=0;
	I2C_SCLK->DATA=1;
	usleep(10);
	a=I2C_DAT->DATA;
	if(a==0)
	{
		printf("slave replay second byte!\n");
	}
	else
		printf("slave no replay !\n");

	I2C_DAT->DIRECTION=1;
	I2C_SCLK->DATA=0;
	usleep(10);
	for(i=0;i<8;i++)//send third byte
	{
		I2C_DAT->DATA=(z & 0x80)?1:0;
		usleep(10);
		I2C_SCLK->DATA=1;
		z=z<<1;
		usleep(10);
		I2C_SCLK->DATA=0;
	}
	I2C_DAT->DIRECTION=0;
	I2C_SCLK->DATA=1;
	usleep(10);
	a=I2C_DAT->DATA;
	if(a==0)
	{
		printf("slave replay third byte!\n");
	}
	else
		printf("slave no replay !\n");

	I2C_DAT->DIRECTION=1;
	I2C_SCLK->DATA=0;
	I2C_DAT->DATA=0;
	I2C_SCLK->DATA=1;
	usleep(10);
	I2C_DAT->DATA=1;//form the stop bit

	return 0;
}

uc wav_init()
{
	uc i=0;
	for(i=0;i<4;i++)
	{
	  WAV_RIFF_CHUNK.RIFF_ID[i]=data_buffer1[i];
	   WAV_RIFF_CHUNK.RIFF_TYPE[i]=data_buffer1[i+8];
	}
	WAV_RIFF_CHUNK. WAV_SIZE=data_buffer1[4]|(data_buffer1[5]<<8)|(data_buffer1[6]<<16)|(data_buffer1[24]);

	for(i=0;i<4;i++)
	{
	   WAV_FORMAT_CHUNK.FORMAT_ID[i]=data_buffer1[i+12];
	}
	WAV_FORMAT_CHUNK.FORMAT_SIZE=data_buffer1[16]|(data_buffer1[17]<<8)|(data_buffer1[18]<<16)|(data_buffer1[19]<<24);
	WAV_FORMAT_CHUNK.FORMAT_TAG=data_buffer1[20]|(data_buffer1[21]<<8);
	WAV_FORMAT_CHUNK.CHANNELS=data_buffer1[22]|(data_buffer1[23]<<8);
	WAV_FORMAT_CHUNK.SAMPLES_PER_SEC=data_buffer1[24]|(data_buffer1[25]<<8)|(data_buffer1[26]<<16)|(data_buffer1[27]<<24);
	WAV_FORMAT_CHUNK.BYTE_PER_SEC=data_buffer1[28]|(data_buffer1[29]<<8)|(data_buffer1[30]<<16)|(data_buffer1[31]<<24);
	WAV_FORMAT_CHUNK.BLOCK_ALIGN=data_buffer1[32]|(data_buffer1[33]<<8);
	WAV_FORMAT_CHUNK.BITS_PER_SAMPLE=data_buffer1[34]|(data_buffer1[35]<<8);
	WAV_FORMAT_CHUNK.ADDITION=data_buffer1[36]|(data_buffer1[37]<<8);

	for(i=0;i<4;i++)
	{
	  WAV_FACT_CHUNK.FACT_ID[i]=data_buffer1[i+38];
	}
	 WAV_FACT_CHUNK.FACT_SIZE=data_buffer1[42]|(data_buffer1[43]<<8)|(data_buffer1[44]<<16)|(data_buffer1[45]<<24);
	 WAV_FACT_CHUNK.FACT_DATA=data_buffer1[46]|(data_buffer1[47]<<8)|(data_buffer1[48]<<16)|(data_buffer1[49]<<24);

	 for(i=0;i<4;i++)
	 {
	    WAV_DATA_CHUNK.DATA_ID[i]=data_buffer1[i+50];
	 }
	 WAV_DATA_CHUNK.DATA_SIZE=data_buffer1[54]|(data_buffer1[55]<<8)|(data_buffer1[56]<<16)|(data_buffer1[57]<<24);

	 return 0;
}

uc wm8731_init()
{
	i2c_send_3byte(0x34,0x1e,0x00);//reset 8731
	i2c_send_3byte(0x34,0x12,0x00);//inactive
	i2c_send_3byte(0x34,0x00,0x17);//left volume
	i2c_send_3byte(0x34,0x02,0x17);//right volume
	i2c_send_3byte(0x34,0x04,0x7b);//left headphone
	i2c_send_3byte(0x34,0x06,0x7b);//right headphone
	i2c_send_3byte(0x34,0x08,0x3d);//select DAC channel
	i2c_send_3byte(0x34,0x0a,0x00);//do not quiet
	i2c_send_3byte(0x34,0x0c,0x00);//power on the device
	i2c_send_3byte(0x34,0x0e,0x41);//master ,16bit and left mode
	i2c_send_3byte(0x34,0x10,0x0c);//sampling clock control set normal mode,8KHZ
	i2c_send_3byte(0x34,0x12,0x01);//active
	i2c_send_3byte(0x34,0x12,0x00);//inactive
	return 0;
}

uc write_CMD0(void)
{
		uc a=0,i=0;
		SD_CS->DATA=1;
		send_byte(0xff);
		SD_CS->DATA=0;
		send_byte(0x40);
		send_byte(0x00);
		send_byte(0x00);
		send_byte(0x00);
		send_byte(0x00);
		send_byte(0x95);
		do
		{
			a=send_byte(0xff);
			i++;
			if(i==200)
			{
				printf("CMD0 no replay\n");
				break;
			}
		}while(a!=0x01);
		return a;
}
uc send_CMD(uc number,uc x,uc y,uc z,uc w, uc u,uc v,uc r)
{
	uc b=0,i=0;
	SD_CS->DATA=1;
	send_byte_fast(0xff);
	SD_CS->DATA=0;
	send_byte_fast(x);
	send_byte_fast(y);
	send_byte_fast(z);
	send_byte_fast(w);
	send_byte_fast(u);
	send_byte_fast(v);
	do
	{
		b=send_byte_fast(0xff);
		i++;
		if(i==200)
		{
			printf("CMD%d no replay\n",number);
			break;
		}
	}while(b!=r);
	return b;
}
uc write_CMD1(void)
{
	uc a=0,i=0;
	SD_CS->DATA=1;
	send_byte(0xff);
	SD_CS->DATA=0;
	send_byte(0x41);
	send_byte(0x00);
	send_byte(0x00);
	send_byte(0x00);
	send_byte(0x00);
	send_byte(0xff);
	do
	{
		a=send_byte(0xff);
		i++;
		if(i==200)
		{
			printf("CMD1 no replay\n");
			break;
		}
	}while(a!=0x00);
	return a;
}

uc sd_init(void)
{
	uc i=0;
	uc a,b;
	SD_CS->DATA=1;
	for(i=0;i<100;i++)
	{
		send_byte(0xff);
	}
	usleep(250);
	i=0;
	do
	{
		b=write_CMD0();
		i++;
		if(i==100)
			break;
	}while(b!=0x01);
	printf("CMD0 replay %x\n",b);
	i=0;
	do
		{
			a=write_CMD1();
			i++;
			if(i==100)
				break;
		}while(a!=0x00);
		printf("CMD1 replay %x\n",a);
		i=0;
		do
		{
			a=send_CMD(16,0x50,0x00,0x00,0x02,0x00,0xff,0x00);
			i++;
			if(i==10)
				break;
		}while(a!=0x00);
	printf("CMD16 replay %x\n",a);
	i=0;
	do
	{
		a=send_CMD(59,0x7b,0x00,0x00,0x00,0x00,0xff,0x00);
		i++;
		if(i==10)
			break;
	}while(a!=0x00);
	printf("CMD59 replay %x\n",a);
	i=0;
	do
	{
		a=send_CMD(9,0x49,0x00,0x00,0x00,0x00,0xff,0x00);
		i++;
		if(i==10)
			break;
	}while(a!=0x00);
	printf("CMD9 replay %x\n",a);
	if(a==0x00)
	{
		uc tem=0;
		do
		{
			printf("tem is %x\n",tem);
			tem=send_byte(0xff);
		}while(tem!=0xfe);
		printf("tem is %x\n",tem);
		if(tem==0xfe)
		{
			printf("0xfe is received\n");
			for(i=0;i<16;i++)
			{
				Resp_buffer[i]=send_byte(0xff);
			}
			send_byte(0xff);
			send_byte(0xff);
			SD_CS->DATA=1;
			send_byte(0xff);
		}
	}
	for(i=0;i<16;i++)
	{
		printf("CSD is %x\n",Resp_buffer[i]);
		REG.CSD_DA.CSD[i]=Resp_buffer[i];
	}
	return 0;
}

void ISR_neg(void *context,unsigned long id)
{
/*	i=0;
		do{
			a=send_CMD(17,0x51,(((CLUS_ADDR+512*k)&0xff000000)>>24),(((CLUS_ADDR+512*k)&0x00ff0000)>>16),(((CLUS_ADDR+512*k)&0x0000ff00)>>8),((CLUS_ADDR+512*k)&0xff),0xff,0x00);
			i++;
			if(i==100)
				break;
			}while(a!=0x00);
		if(a==0x00)
		{
			uc temp=0;
			int j=0;;
			do{
				temp=send_byte_fast(0xff);
				j++;
				}while(temp!=0xfe && j<100);*/
	int j;
	for(j=0;j<509;j=j+4)
	{

		data_buffer1[j]=send_byte_fast(0xff);
		data_buffer1[j+1]=send_byte_fast(0xff);
		data_buffer1[j+2]=send_byte_fast(0xff);
		data_buffer1[j+3]=send_byte_fast(0xff);
		if((data_buffer1[0]==0x52) && (data_buffer1[1]=0x49) && (data_buffer1[2]==0x46) && (data_buffer1[3]==0x46))
		{
		    if(j>=58)
		    {
			WR_EN->DATA=0;
			WR_DAT->DATA=data_buffer1[j]|(data_buffer1[j+1]<<8)|(data_buffer1[j+2]<<16)|(data_buffer1[j+3]<<24);
			WR_EN->DATA=1;
		    }
		}
		else
		{
			WR_EN->DATA=0;
			WR_DAT->DATA=data_buffer1[j]|(data_buffer1[j+1]<<8)|(data_buffer1[j+2]<<16)|(data_buffer1[j+3]<<24);
			WR_EN->DATA=1;
		}
	}
}

int init_neg(void)
{
	WR_USE_W->INTERRUPT_MASK=1;
	return alt_irq_register(WR_USE_W_IRQ,NULL,ISR_neg);
}

//*********************************************************************************************************************************************
//the main function
int main()
{
  int i=0,j=0,k=0,cnt=0;
  unsigned int index=0;
  uc a;
  for(i=0;i<8;i++)
  {
      LED->DATA=1<<i;
      usleep(500000);
  }
    SD_CS->DATA=1;
    SD_CMD->DIRECTION=1;
    SD_CMD->DATA=1;

    sd_init();
    wm8731_init();
    i=0;
    do
    {
    	a=send_CMD(10,0x4a,0x00,0x00,0x00,0x00,0xff,0x00);
    	i++;
    	if(i==10)
    		break;
    }while(a!=0x00);
    printf("CMD10 replay %x\n",a);
    if(a==0x00)
    {
    	uc tem=0;
    	do
    	{
    		printf("tem is %x\n",tem);
    		tem=send_byte(0xff);
    	}while(tem!=0xfe);
    	printf("tem is %x\n",tem);
    	if(tem==0xfe)
    	{
    		printf("0xfe is received\n");
    		for(i=0;i<16;i++)
    		{

    			Resp_buffer[i]=send_byte(0xff);
    		}
    		send_byte(0xff);
    		send_byte(0xff);
    		SD_CS->DATA=1;
    		send_byte(0xff);
    	}
    	for(i=0;i<16;i++)
    	{
    		printf("CID is %x\n",Resp_buffer[i]);
    		REG.CID_DA.buf1[i]=Resp_buffer[i];
    	}
    }

    i=0;
	do
	{
		a=send_CMD(17,0x51,0x00,0x00,0x00,0x00,0xff,0x00);
		i++;
		if(i==100)
			break;
	}while(a!=0x00);
	printf("CMD17 replay %x\n",a);
	if(a==0x00)
	{
		uc temp=0;
		int j=0;;
		do{
			printf("temp is %x\n",temp);
			temp=send_byte_fast(0xff);
			j++;
		}while(temp!=0xfe && j<100);
	printf("temp is %x\n",temp);
	if(temp==0xfe)
	{
		printf("0xfe is received\n");
		printf("block 0 data is followed\n");
		for(j=0;j<512;j++)
		{

			data_buffer[j]=send_byte_fast(0xff);
		}
		i=0;
		for(j=0;j<512;j++)
		{
			printf("%x ",data_buffer[j]);
			i++;
			if(i==16)
			{
				i=0;
				printf("\n");
			}
		}
	}
    }
	if((data_buffer[0]==0x00)||(data_buffer[0]!=0xeb)||(data_buffer[0]!=0xe9))//judge the weather first block is DBR or not
	{

		DBR_ADDR=(((DBR_ADDR|data_buffer[457])<<24)|((DBR_ADDR|data_buffer[456])<<16)|((DBR_ADDR|data_buffer[455])<<8)|data_buffer[454])*512;
		i=0;
		do{
			a=send_CMD(17,0x51,((DBR_ADDR&0xff000000)>>24),((DBR_ADDR&0x00ff0000)>>16),((DBR_ADDR&0x0000ff00)>>8),(DBR_ADDR&0xff),0xff,0x00);
			i++;
			if(i==100)
				break;
			}while(a!=0x00);
		if(a==0x00)
		{
			uc temp=0;
			int j=0;;
			do{
				printf("temp is %x\n",temp);
				temp=send_byte_fast(0xff);
				j++;
				}while(temp!=0xfe && j<100);
				printf("temp is %x\n",temp);
				if(temp==0xfe)
				{
					printf("0xfe is received\n");
					printf("DBR data is followed\n");
					for(j=0;j<512;j++)
					{

						data_buffer[j]=send_byte_fast(0xff);
					}
					i=0;
					for(j=0;j<512;j++)
					{
						printf("%x ",data_buffer[j]);
						i++;
						if(i==16)
						{
							i=0;
							printf("\n");
						}
					}

				}
			}
		}
		else
		{
			DBR_ADDR=0;
		}
		FAT1_ADDR=DBR_ADDR+((data_buffer[14]|(data_buffer[15]<<8))*512);
		FAT2_ADDR=FAT1_ADDR+((data_buffer[36]|(data_buffer[37]<<8))*512);
		FDT_ADDR=FAT2_ADDR+((data_buffer[36]|(data_buffer[37]<<8))*512);
		CLUS_LEN=data_buffer[13]*512;
		printf("FAT1_ADDR is %lx \n",FAT1_ADDR);
		printf("FAT2_ADDR is %lx \n",FAT2_ADDR);
		printf("FDT_ADDR is %lx \n",FDT_ADDR);
		printf("DBR_ADDR is %lx \n",DBR_ADDR);
		printf("CLUS_LEN is %lx \n",CLUS_LEN);
		i=0;
		do{
			//read the FDT
			a=send_CMD(17,0x51,((FDT_ADDR&0xff000000)>>24),((FDT_ADDR&0x00ff0000)>>16),((FDT_ADDR&0x0000ff00)>>8),(FDT_ADDR&0xff),0xff,0x00);
			i++;
			if(i==100)
				break;
			}while(a!=0x00);
		if(a==0x00)
		{
			uc temp=0;
			int j=0;
			do{
				printf("temp is %x\n",temp);
				temp=send_byte_fast(0xff);
				j++;
				}while(temp!=0xfe && j<100);
				printf("temp is %x\n",temp);
				if(temp==0xfe)
				{
					printf("0xfe is received\n");
					printf("FDT data is followed\n");
					for(j=0;j<512;j++)
					{
						data_buffer[j]=send_byte_fast(0xff);
					}
				i=0;
				for(j=0;j<512;j++)
				{
					printf("%x ",data_buffer[j]);
					i++;
					if(i==16)
					{
						i=0;
						printf("\n");
					}
				}
			}
		}
	for(i=0,j=0;i<512;i=i+32)
	{
		if((data_buffer[11+i]==0x08)&&(data_buffer[i]!=0xe5))//find the juan biao
		{
			printf("juan biao is %d\n",i+11);
			continue;
		}
		else if((data_buffer[11+i]==0x20)&&(data_buffer[i]!=0xe5))//find the file
		{
			CLUS_CURRENT=(data_buffer[20+i]<<16)|(data_buffer[21+i]<<24)|(data_buffer[27+i]<<8)|(data_buffer[26+i]);//first clus addr
			printf("first clus is %ld\n",CLUS_CURRENT);
			FDT_DIRECT[j]=CLUS_CURRENT;//store the current clus addr
			j++;
			continue;
		}
		else if(data_buffer[i]==0xe5)
			continue;
		else if(data_buffer[i]==0x00)
		{
			break;
			not_finish=0;//no file behind
		}
	}
	i=0;
	do{
		//read FAT1
		a=send_CMD(17,0x51,((FAT1_ADDR&0xff000000)>>24),((FAT1_ADDR&0x00ff0000)>>16),((FAT1_ADDR&0x0000ff00)>>8),(FAT1_ADDR&0xff),0xff,0x00);
		i++;
		if(i==100)
			break;
		}while(a!=0x00);
	if(a==0x00)
	{
		uc temp=0;
		int j=0;;
		do{
			printf("temp is %x\n",temp);
			temp=send_byte_fast(0xff);
			j++;
			}while(temp!=0xfe && j<100);
			printf("temp is %x\n",temp);
			if(temp==0xfe)
			{
				printf("0xfe is received\n");
				printf("FAT1 data is followed\n");
				for(j=0;j<512;j++)
				{
					data_buffer[j]=send_byte_fast(0xff);
				}
			i=0;
			for(j=0;j<512;j++)
			{
				printf("%x ",data_buffer[j]);
				i++;
				if(i==16)
				{
					i=0;
					printf("\n");
				}
			}

		}
	}
	CLUS_ADDR=(FDT_DIRECT[0]-2)*CLUS_LEN+FDT_ADDR;//first data clus address
	CLUS_NEXT=data_buffer[(FDT_DIRECT[0]*4)]|(data_buffer[(FDT_DIRECT[0]*4+1)]<<8)|(data_buffer[(FDT_DIRECT[0]*4+2)]<<16)|(data_buffer[(FDT_DIRECT[0]*4+3)]<<24);
//	CLUS_ADDR=(CLUS_CURRENT-2)*CLUS_LEN+FDT_ADDR;//first data clus address
//	CLUS_NEXT=data_buffer[CLUS_CURRENT*4]|(data_buffer[CLUS_CURRENT*4+1]<<8)|(data_buffer[CLUS_CURRENT*4+2]<<16)|(data_buffer[CLUS_CURRENT*4+3]<<24);
//	printf("CLUS_NEXT is %lx\n",CLUS_NEXT);
	index=0;
	cnt=0;
	do{
	do{
		CLUS_ADDR=(FDT_DIRECT[cnt]-2)*CLUS_LEN+FDT_ADDR;//first data clus address
		FDT_DIRECT[cnt]=CLUS_NEXT;
		CLUS_NEXT=FDT_DIRECT[cnt]+1;//data_buffer[(FDT_DIRECT[cnt]*4-512*index)]|(data_buffer[(FDT_DIRECT[cnt]*4+1-512*index)]<<8)|(data_buffer[(FDT_DIRECT[cnt]*4+2-512*index)]<<16)|(data_buffer[(FDT_DIRECT[cnt]*4+3-512*index)]<<24);
//		FDT_DIRECT[cnt]=CLUS_NEXT;
/*		if((FDT_DIRECT[cnt]*4+3)>=511)
		{
			FDT_DIRECT[cnt]=0;
			index++;
			i=0;
			do{
				//read FAT1 next 512 byte
				a=send_CMD(17,0x51,(((FAT1_ADDR+512*index)&0xff000000)>>24),(((FAT1_ADDR+512*index)&0x00ff0000)>>16),(((FAT1_ADDR+512*index)&0x0000ff00)>>8),((FAT1_ADDR+512*index)&0xff),0xff,0x00);
				i++;
				if(i==100)
					break;
				}while(a!=0x00);
			printf("a is %x\n",a);
			if(a==0x00)
			{
				uc temp=0;
				int j=0;;
				do{
					printf("temp is %x\n",temp);
					temp=send_byte_fast(0xff);
					j++;
					}while(temp!=0xfe && j<100);
					printf("temp is %x\n",temp);
					if(temp==0xfe)
					{
						printf("0xfe is received\n");
						printf("FAT1 next 512b data is followed\n");
						for(j=0;j<512;j++)
						{
							data_buffer[j]=send_byte_fast(0xff);
						}
						i=0;
						for(j=0;j<512;j++)
						{
							printf("%x ",data_buffer[j]);
							i++;
							if(i==16)
							{
								i=0;
								printf("\n");
							}
						}

				}
			}
		}*/
//		CLUS_ADDR=(CLUS_CURRENT-2)*CLUS_LEN+FDT_ADDR;
//		CLUS_CURRENT=CLUS_NEXT;
//		CLUS_NEXT=data_buffer[CLUS_CURRENT*4]|(data_buffer[CLUS_CURRENT*4+1]<<8)|(data_buffer[CLUS_CURRENT*4+2]<<16)|(data_buffer[CLUS_CURRENT*4+3]<<24);
//		for(k=0;k<8;k++)//for each clus has 8 512Byte
//		{
			k=0;
			while(!WR_USE_W->DATA)
			{
			i=0;
			do{
			a=send_CMD(17,0x51,(((CLUS_ADDR+512*k)&0xff000000)>>24),(((CLUS_ADDR+512*k)&0x00ff0000)>>16),(((CLUS_ADDR+512*k)&0x0000ff00)>>8),((CLUS_ADDR+512*k)&0xff),0xff,0x00);
			i++;
			if(i==100)
				break;
			}while(a!=0x00);
//			printf("read data a is %x\n",a);
			if(a==0x00)
			{
				uc temp=0;
				int j=0;
				do{
//					printf("temp is %x\n",temp);
					temp=send_byte_fast(0xff);
					j++;
					}while(temp!=0xfe && j<100);
//					printf("temp is %x\n",temp);
					if(temp==0xfe)
					{
//						printf("0xfe is received\n");
//						printf("first clus data is followed\n");
						for(j=0;j<509;j=j+4)
						{

							data_buffer1[j]=send_byte_fast(0xff);
							data_buffer1[j+1]=send_byte_fast(0xff);
							data_buffer1[j+2]=send_byte_fast(0xff);
							data_buffer1[j+3]=send_byte_fast(0xff);
							if((data_buffer1[0]==0x52) && (data_buffer1[1]=0x49) && (data_buffer1[2]==0x46) && (data_buffer1[3]==0x46))
							{
								if(j>=58)
								{
									WR_EN->DATA=0;
									WR_DAT->DATA=data_buffer1[j]|(data_buffer1[j+1]<<8)|(data_buffer1[j+2]<<16)|(data_buffer1[j+3]<<24);
									WR_EN->DATA=1;
							    }
							}
							else
							{
								WR_EN->DATA=0;
								WR_DAT->DATA=data_buffer1[j]|(data_buffer1[j+1]<<8)|(data_buffer1[j+2]<<16)|(data_buffer1[j+3]<<24);
								WR_EN->DATA=1;
							}
						}
/*					i=0;
					for(j=0;j<512;j++)
					{
						usleep(10);
						printf("%x ",data_buffer1[j]);
						i++;
						if(i==16)
						{
							i=0;
							printf("\n");
						}
					}*/

				}
			}
			k++;
//			if(k==8)
//				break;
			}
			i2c_send_3byte(0x34,0x12,0x01);//active
//			printf("enable display!\n");
//			while(WR_USE_W->DATA);
			while(1)
			{
				while(!WR_USE_W->DATA)
				{
					i=0;
					do{
					a=send_CMD(17,0x51,(((CLUS_ADDR+512*k)&0xff000000)>>24),(((CLUS_ADDR+512*k)&0x00ff0000)>>16),(((CLUS_ADDR+512*k)&0x0000ff00)>>8),((CLUS_ADDR+512*k)&0xff),0xff,0x00);
					i++;
					if(i==100)
						break;
					}while(a!=0x00);
					if(a==0x00)
					{
						uc temp=0;
						int j=0;
						do{
		//					printf("temp is %x\n",temp);
							temp=send_byte_fast(0xff);
							j++;
							}while(temp!=0xfe && j<100);
		//					printf("temp is %x\n",temp);
							if(temp==0xfe)
							{
		//						printf("0xfe is received\n");
		//						printf("first clus data is followed\n");
								for(j=0;j<509;j=j+4)
								{

									data_buffer1[j]=send_byte_fast(0xff);
									data_buffer1[j+1]=send_byte_fast(0xff);
									data_buffer1[j+2]=send_byte_fast(0xff);
									data_buffer1[j+3]=send_byte_fast(0xff);
/*									if((data_buffer1[0]==0x52) && (data_buffer1[1]=0x49) && (data_buffer1[2]==0x46) && (data_buffer1[3]==0x46))
									{
										if(j>=58)
										{
											WR_EN->DATA=0;
											WR_DAT->DATA=data_buffer1[j]|(data_buffer1[j+1]<<8)|(data_buffer1[j+2]<<16)|(data_buffer1[j+3]<<24);
											WR_EN->DATA=1;
									    }
									}*/
//									else
//									{
										WR_EN->DATA=0;
										WR_DAT->DATA=data_buffer1[j]|(data_buffer1[j+1]<<8)|(data_buffer1[j+2]<<16)|(data_buffer1[j+3]<<24);
										WR_EN->DATA=1;
//									}
								}
							}
					}
					k++;
					if(k==8)
						break;
				}
				if(k==8)
					break;
			}
//	} //the for loop
	}while(CLUS_NEXT!=0x0fffffff);
	cnt++;
	CLUS_NEXT=data_buffer[(FDT_DIRECT[cnt]*4)]|(data_buffer[(FDT_DIRECT[cnt]*4+1)]<<8)|(data_buffer[(FDT_DIRECT[cnt]*4+2)]<<16)|(data_buffer[(FDT_DIRECT[cnt]*4+3)]<<24);
	}while(FDT_DIRECT[cnt]!=0);
		SD_CS->DATA=1;
		unsigned long int cap;
		double  c;
		//(c_size+1)*mult*(1<<read_bl_len)
		cap=((((REG.CSD_DA.CSD[6]&0x03)<<10) | (REG.CSD_DA.CSD[7]<<2) | ((REG.CSD_DA.CSD[8]&0xC0)>>6) + 1))*(1 << ((((REG.CSD_DA.CSD[9]&0x03)<<1) | ((REG.CSD_DA.CSD[10]&0x80)>>7)) + 2))*(1<<(REG.CSD_DA.CSD[5]&0x0f));
		printf("capacity is %ld MB\n",cap/1048576);
		printf("read_bl_len is %d B\n",(1<<(REG.CSD_DA.CSD[5]&0x0f)));
		c=((double)cap/1073741824);
		printf("capacity is %f GB\n",c);
    printf("send CMD0!\n");
  return 0;

}

   有很多没用到的引脚,我没删除,留着扩展用吧,另外我没用中断,虽然生命了函数,但是是用电平检测来做的,担心中断容易出BUG。

  采样频率没法再提高了,SD卡读取还是比较慢的,我尝试了32K和48K ,都失败了,放出来的声音简直是闹鬼,不过我同学说,8K的效果也很不错了,一点噪音没有。

  播放结束后,手动按复位键重新开始播放,不然会将卡里的数据都用DAC播放出来,呵呵,我没检测文件簇结束标志0X0FFFFFFF,所以它会一直不停的播放下去,我也懒得改了。 

我觉得应该有办法将采样频率提高到48K的,因为友晶的范例是用的44.1K的采样频率,我这篇是原创,完全没有按他们的思路来。从电路到程序全是自己搞的。

posted @ 2011-09-01 15:14  lamapig  阅读(3048)  评论(7编辑  收藏  举报