准备工具:格式工厂,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的采样频率,我这篇是原创,完全没有按他们的思路来。从电路到程序全是自己搞的。