这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 两次DIY多功能MP3的资料整理以及对比分析

共16条 1/2 1 2 跳转至

两次DIY多功能MP3的资料整理以及对比分析

高工
2013-12-30 10:18:45     打赏

最近整理了这方面的资料,发现有些东西值得拿出来共享一下,所以在此整理下资料和对比两次所用的一些模块和资料。

1.曾经的开发进程:http://forum.eepw.com.cn/thread/220095/1

主控:瑞萨RL78/G13 

音频解码模块:VS1003B

显示:TFT彩屏2.4寸

SD卡:1G的SD卡,FAT32文件系统

文件级操作所用文件:精简版znFAT

功能:音乐播放,以及图片浏览和文本阅读



2.曾经共享过的帖子:http://forum.eepw.com.cn/thread/235725/1

主控:STM32F103ZET6

音频解码模块:VS1053

显示:TFT彩屏2.8寸

SD卡:4G的SD卡,FAT32文件系统

文件级操作所用文件:znFAT完整版

操作系统:ucos_ii

界面:ucgui



在音频解码模块方面,两个模块的操作方法基本上一样,只是我们除了让它解码音频文件,一般都希望能够读取出频谱数据,这样更加绚丽。两款模块都是先写入补丁代码之后,便可以读取出14个频谱数据。在做第二的时候以为俩模块要写入的补丁文件是一样的,结果是木有任何反应,之后在网上搜到了两外一版补丁文件。

VS1003b的补丁代码可以查看代码里的plug.h。写入补丁以及读取频谱的函数如下:

void  WriteVS1003Plug()
{
    
     uint16 i;
     VS1003SetXDCS();
    for(i = 0;i < 945;i++)
    {
        VS1003WriteRegister(atab[i],(dtab[i] >> 8),(dtab[i] & 0xff));
    }
}

void  ReadVs1003Plug(uint8 *rBuffer)
{
    uint8 i;
    VS1003SetXDCS();
    VS1003WriteRegister(VS_WRAMADDR,0x18,0x04);
    for(i = 0;i < 14;i++)
    {
        *rBuffer++ = VS1003ReadRegister(VS_WRAM);
    }
    VS1003ClrXDCS();
}

 

VS1053的补丁文件见代码里的SPEC_REW.H,写入与读取函数如下:

void  WriteVS1003Plug()
{ 
    u16 i;
    for(i = 0;i < 970;i++)
    {
        VS_WR_Cmd(atab[i],dtab[i]);
    }
}


#define Spec_Base 0x1810
u8  ReadVs1003Plug(u16 *p)
{
	u8 byteIndex=0;
	u16 bands; 
	OS_CPU_SR cpu_sr=0;
	OS_ENTER_CRITICAL();
	VS_WR_Cmd(SPI_WRAMADDR,Spec_Base+2);
	bands=VS_RD_Reg(SPI_WRAM); 
	bands=14; 
	VS_WR_Cmd(SPI_WRAMADDR,Spec_Base+4); 	                                                                                            
	for (byteIndex=0;byteIndex<14;byteIndex++) 
	{                                                                     
		*p++=VS_RD_Reg(SPI_WRAM);	 	
	}
	OS_EXIT_CRITICAL();
	return bands;
}

 


SD卡第一次用的是1G的SD卡,第二次用的是4G的SD卡,,这就有本质的区别了哟,在用4G的SD卡时还没有大容量SD卡的概念,所以直接用之前的代码去操作,结果就是咋整都整不出来,在网上逛了逛发现这俩所用的协议是不同的。所以之后采用了SD卡的v2.0协议去操作4G的SD卡.以下是我对V2.0协议的一些总结:

现在使用的4G的SD卡,小于或等于2G的卡是属于标准SD卡,而大于2G的卡小于32G的卡是大容量SD卡,也就是SDHC卡。对于SDHC卡的初始化和操作要使用V2.0协议。首先是一个流程图,这个图在官方资料上有:

SPI模式下SD卡部分操作指令

命令

参数

回应

描述

CM0(0X00)

NONE

R1

复位SD

CMD9(0X09)

NONE

R1

读取卡特定寄存器

CMD10(0X0A)

NONE

R1

读取卡标志寄存器

CMD16(0X10)

块大小

R1

设置块的大小(字节数)

CMD17(0X11)

地址

R1

读取一块的数据

CMD24(0X18)

地址

R1

写入一块的数据

CMD41(0X29)

NONE

R1

开始卡的初始化

CMD55(0X37)

NONE

R1

引用命令的前命令

CMD59(0X3B)

最后一位有效

R1

设置CRC开启(1)或关闭(0



SD卡R1回应格式:

BIT7

BIT6

BIT5

BIT4

BIT3

BIT2

BIT1

BIT0

0

参数错误

地址错误

连续擦除错误

命令CRC错误

非法命令

擦除复位

IDLE状态



卡会根据不同的时候处在不同的状态


第一步操作: 复位
SD卡上电后先发送(>74个时钟),因为SD卡有个供电电压上升过程需要大约64个时钟,之后的10个时钟是用来与SD卡同步(参考《例说STM32》)。参考代码:

for(count = 0;count < 15;count++)
SPI_WriteReadByte(0xff); //产生74个以上的脉冲

 


SD卡默认是SD模式,现在用STM32去操作,切换为SPI模式后更好操作。所以在片选为低时发送CMD0,此时卡进入IDLE状态,因为CMD0回应的命令是R1,根据上面R1的回应格式可以看出我们自需要检查最低位就知道是否处于IDLE状态。参考代码:
do
{
tmp = SD_WriteCommand(CMD0,0,0X95); //发送SD
count++;
}while((tmp != 0x01) && (count < DISPLAY_COUNT)); 

 


第二步操作发送CMD8来分辨卡的类型,是V2.0卡还是V1.0卡或MMC卡,还可以检测CMD8响应返回的数据判断是否支持给定的工作电压范围。
根据流程图可以看出。
1.如果SD卡支持当前的电压就会返回R7,并包含CMD8的参数部分,其中包括:Check voltage和check pattern。
2.如果SD卡不支持当前的工作电压则不会返回任何响应信息,继续处在IDLE状态。如果是V1.0x的SD卡也不会有响应。
3.在PLV2.0(physical layer version2.0)下,在首次执行ACMD41之前,必须执行CMD8指令,用以初始化SDHC卡,SDHC卡根据是否接收到CMD8指令来鉴别控制器是否支持PLV2.0协议。使用低电压的控制器也必须在ACMD41命令之前发送CMD8,避免可以工作在两种电压模式下的SD卡因为没有接收到CMD8, 而默认工作在高电压环境下,被误认为是只支持高电压工作模式。

Application Note:
It is recommended to use ‘10101010b’ for the ‘check pattern’.
R7的格式:

从上面可以看到,R7为5个字节,在发送CMD8后,SD卡响应,发送回来的第一个字节就是R1,之后的4个字节中就包含了Check voltage和check pattern。下面是仿真的结果:

判断Check voltage按照如下标准:

根据流程图就可以看出发送CMD8后SD卡的类型基本上分了两类。


第三步:由ACMD41来初始化SD卡,SD卡的初始化从收到ACMD41开始。
ACMD指令的HCS(Host Capacity Support)位如果设定为1的话,表明控制器支持SDHC卡,否则表示不支持。
SD卡初始化和识别过程:
在CMD8命令发送之后的ACMD41指令其功能有所扩展,在参数里多了HCS部分,在响应里面多了CCS(Card Capacity Status)部分。HCS参数会被不响应CMD8命令的SD卡所抛弃。控制器向不响应CMD8的卡发送ACMD41指令时,HCS位应该设置为零0。如果向SDHC卡发送HCS位为0的ACMD41命令,SDHC卡返回的响应,其busy标识位永远为0,代表忙状态。HCS标识位用来表明SD卡是否已经完成初始化,如果未完成,HCS为零,否则为1,如果HCS为0,控制器会重复发送ACMD41指令,SD卡只检查首次接收到的ACMD41指令的HCS位。
按照流程图,现在发送ACMD41可以用来分辨是否为高容量卡。

SD_WriteCommand(CMD41,0x40000000,0X01);//发送ACMD41,流程图写的如果主机支持大容量就将HCS置1.所以发送0x40000000
因为ACMD41为应用型指令,所以前面要加上CMD55一起使用。
SD_WriteCommand(CMD55,0,0x01);
SD_WriteCommand(CMD41,0x40000000,0X01);
一直发送这两条指令,直到卡准备好。处于Ready状态。
所以接收到响应为0之后就可以开始读取OCR信息。并检测bit30位(CCS位),如果此位是1就是高容量卡,如果为0则是标准SD卡。读取OCR的指令是CMD58,其响应是R3:

前面的R1应该为0。
之后再接收4个字节的数据。并判断bit30位。就可以判断是SDV2.0还是SDV2.0HC。初始化完成。

最后要注意的是扇区的地址是不同的。




图片解码方面都是只解码了BMP格式文件。

第一步:判断是否为BMP格式图片
根据BMP格式的编码信息可以得到,只要是BMP格式的图片,前两个字节就是'B'和'M'。大家可以看编码信息,第一个字节和第二个字节就是B和M的ASCii码。

第二步:得出图像数据的起始位置相对于文件开头的偏移量
这一步的目的是什么呢,就是确定真正的图像数据是从第几个字节开始的。
在BMP格式编码信息的前14个字节里就有偏移量这个信息,那么到底是那几个字节是偏移量的信息呢。现在看看编码格式:
BMP的文件信息: 文件开头的14个字节
WORD BMPId;BMP文件标志,其值固定为0x4d42,即“BM”(两个字节)
DWORD FileSize;BMP文件大小,以字节为单位 (4个字节)
WORD Reserved1;BMP文件保留字,必须为0 (两个字节)
WORD Reserved2;BMP文件保留字,必须为0 (两个字节)
DWORD ImageOffset;图像数据的起始位置相对于文件开头的偏移量 (4个字节)
偏移量的信息是在这14个字节数据中的最后4个。

第三步:得出BMP格式图片是多少位和图片的像素
在上面的14个字节后还有40个字节的信息可以给我们分析。我们只需要分析出我们需要的信息。现在看下面的信息有哪些:
Bmpinfoheader 文件信息之后的40个字节
DWORD HeaderSize;BMP图像信息大小(40或12),以字节为单位 (4个字节)
DWORD ImageWidth;BMP图像宽度,以像素为单位 (4个字节)
DWORD ImageHeight;BMP图像高度,以像素为单位 (4个字节)
WORD EquipLevel;目标设备的级别(色彩平面数),固定为1 (2个字节)
WORD BitsPerPixel;每个像素所需要的位数,1,4,8,24 (2个字节)
DWORD EncodeType; 压缩类型,0(不压缩),1(BI_RLE8),2(BI_RLE4) (4个字节)
DWORD ImageSize; BMP位图大小,以字节为单位 (4个字节)
DWORD XPixelPerMeter设备水平分辨率(每米像素数) (4个字节)
DWORD YPixelPerMeter设备垂直分辨率(每米像素数) (4个字节)
DWORD ColorUsed实际使用色彩数目,若为0,则由位数定 (4个字节)
DWORD ColorImportant图像中重要的色彩数目。为0,表示调色板内所有的颜色都是重要的 (4个字节)

第四步:根据不同的位图来用不同的函数求出彩屏需要的RGB显示值
我们知道的偏移量,那么真正要显示的数据就是,从偏移量那里开始后面的字节就是我们图片的显示数据。显示数据的大小就是我们上面所求的BMP位图大小。彩屏液晶上面的每个像素点都是一个16位的数据,这16位的数据包含了该点的RGB的值。那么我们怎么根据图片里的数据来求出RGB的值并转化为一个16位的数据呢!
首先说32位的BMP图片:
32位的图片是一个像素点的信息由4个字节表示。
BYTE rgbBlue; (B)
BYTE rgbGreen; (G)
BYTE rgbRed; (R)




获取歌曲信息,在第一次制作过程中采用的方式是去分析MP3的编码方式然后去读取歌曲名和相关信息。详细的可以查看进程贴。第二次是直接利用znFAT里面的长文件名读取,这样就缩短了很长的时间。


歌词显示方面,在第一次的制作中由于主控速度太慢的原因没有加入歌词显示。在第二次就加入了歌词显示功能,在处理歌词方面采用这样步骤:在播放歌曲前先获取歌词文件中所有的标签点保存下来。在歌曲播放期间就不需要再去判断标签内容了,只需要匹配时间点,那两种音频解码模块都可以读取时间单位为秒。这样处理可以节省时间但是浪费存储空间。



第一次采用的是精简版znFAT,只有两个文件,第二次采用的是完整版的。后者能对大容量SD卡进行操作并且有可裁剪性。相比fatfs来说增加了中文字符编码的转换,所以fatfs相对来说比较小,但是fatfs也可以裁剪,这点不弱于znfat。



两次的文本显示都涉及到中文和英文字符的判断,一旦将中文编码拆散就会导致之后的文字都乱码,第二次利用UCGUI的控件来装文本,还得手动插入字符,这部分挺麻烦也挺好玩。

先整理这么多,代码早已共享,可以去相应帖子查看。有些总结可能不好,欢迎拍砖




关键词: 资料     整理     对比     分析    

院士
2013-12-30 11:13:16     打赏
2楼
其实这都可以弄一篇好的文章分享给大家了

专家
2013-12-30 17:01:35     打赏
3楼
学习了,看来sd卡学问还是蛮大的

工程师
2013-12-30 21:57:50     打赏
4楼
顶一个~~~虽然还不懂~~

专家
2013-12-30 21:59:40     打赏
5楼

歪头企鹅            


高工
2014-01-02 01:51:07     打赏
6楼

把有用的再整成pdf的再共享


高工
2014-01-02 01:52:13     打赏
7楼

sd卡看起来挺单纯的,里面花花肠子挺多的,呵呵


高工
2014-01-02 01:53:45     打赏
8楼

都是瞎玩玩的


高工
2014-01-02 01:55:38     打赏
9楼
大神,新年礼物有吗,要不赏点积分撒

专家
2014-01-02 08:44:56     打赏
10楼

抽空也玩玩


共16条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]