注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

fancye的博客

 
 
 

日志

 
 

基于CH376的SD卡调试记录(基于NIOS II) 转  

2012-10-29 01:13:23|  分类: 嵌入式 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

http://bbs.ednchina.com/BLOG_ARTICLE_1869497.HTM


                                    


一.调试计划:


1.      创建文件。


2.      向文件中写入数据


3.      打开文件


4.      读取文件


5.      删除文件


6.      枚举文件


7.      向已有文件中追加数据


8.      查询SD卡总容量


9.      查询SD卡剩余容量


10.  查询文件大小


 


二.调试记录


8月19日:


上午调试记录


读取SD容量,调用CH376DiskCapacity()函数,在FILE_SYS.H中需宏定义#define EN_DISK_QUERY。返回的是磁盘总扇区数,转化成字节时需乘以512字节。


 


用FileCreatAndWrite()函数创建文件并向文件中写入数据,提示写入成功。


该 FileCreatAndWrite()函数中创建文件使用函数CH376FileCreate(),既向当前目录下创建文件,文件命名格 式:filename=”xxx.txt”。向文件中写入数据使用函数CH376ByteWrite( pfiledata, size, NULL )。


 


打开文件读取数据采用FileOpenAndRead(ref_u8 *pfilename,ref_u8 *pbuffer,ref_u8 size)函数,其中文件名格式filename=”xxx.txt”,即只能打开当前目录下的文件打开文件读取数据时出现问题:a.有时显示文件没找 到,b.有时文件打开成功,但返回数据长度不正确,察看数据缓冲区发现数据已丢失。


 


下午调试记录


先前已将文件建立好,试着注释掉创建文件并向文件中写入数据那段函数之后,能成功打开文件并正确读取数据。(注:其实后来也不知道什么原因能读出来的,当时文件名是小写,所以本身操作是不合规定的。)


 


采 用结构体数组的形式定义5组文件名,5组数据,创建5个文件,并向创建好的文件中写入定义好的数据,5组数据分别为10字节,15字节,20字节,25字 节,30字节,包含字母与数字。先执行FileCreatAndWrite()函数,成功创建5个文件并分别向其中写入相应数据,注释掉该部分内容,执行 FileOpenAndRead()函数,成功打开刚建的5个文件,正确返回相应的字节数。


 


将两部分内容 连起来,既先调用FileCreatAndWrite()函数接着调用FileOpenAndRead()函数,第一部分能成功进行,提示“创建并数据写 入成功”,但打开文件时提示“文件读取失败”,返回代码0x42(未找到文件提示错误),之间需要延时?延时2秒,还是那错误……


 


后 来将创建文件的函数改成CH376FileCreatePath(),打开文件的函数改成 CH376FileOpenPath(),既支持多路径下的文件操作后,上述问题解决,注意此时字符串格式为”/xx/xx.xx”。(其实两个函数的区 别无非就是文件名关键字的提取,CH376FileCreatePath()分析文件路径,打开一层层目录之后,打开文 件,CH376FileCreate()只能打开当前目录下的文件,至于为什么出错还真查不出原因,先留个记号 。)注:在8月23日调试记录中有说明。


 


晚上调试记录


准 备在早上程序的基础上添加向文件中写入大数据量的功能,手册上说建议单次写入字节数尽量是扇区大小512 的倍数,又最大字节数不超过 65535,综合考虑选择一次能写入的最大字节数为65024。(对于读写操作,SD卡只能进行字节操作,以字节为单位的文件读写子程序,占用RAM 相对较少,能够自动处理文件长度,使用较为方便。尽量缓冲和集中多个零碎数据,然后合并起来成批成块写入,减少擦写次数。建议单次写入字节数尽量是扇区大 小512 的倍数,避免频繁地向U 盘中的文件写入零碎的数据,那样会缩短U盘或者SD 卡中闪存的使用寿命(因为闪存只能进行有限次擦写))


 


8月20日


上午调试记录


读取文件数据得到的字节数之前是未知的,可以函数通过返回值来判断是否已将文件数据全部读完,但写入的字节数如果也是未知的呢,(不高兴去统计要写入多少字节)有办法去判断吗?


 


当 准备一10字节的字符串,但我要求写入20字节,最后返回多少字节呢?后来用读文件数据函数去执行,返回20字节数据,由调试输出可以看到从11字节开始 都为0x00,看来你规定写多少字节他就写多少字节,而且CH376的读字节命令并不以结束符结束的。想到CH376ByteWrite( buf, ReqCount, RealCount )函数中形参RealCount在例程中都是NULL,只是一个空指针,但他有什么用呢,察看沁恒的源函数库发现他返回写入字节长度,它能主动识别出正确 的字符串长度吗,经调试发现他返回的数据也为20,既仍是要求写入的字节数,并不是实际的字节数,暂且想到的方法是在执行向文件写入数据函数之前,用 strlen() 测试一下需写入的字符串长度与实际要求写的字节数比较,如果小于实际要求的字节数,则将测得的字符串长度付给要求的长度变量,经测试此种方法可行。


 


下午调试记录


后来发现一种情况导致推翻了上午的方案,strlen()是不计”\0”的长度的,既遇到0x00就停止了,当那一串字符串中有0 时,strlen()会做出错误的判断。所以上午的方案不可行。


 


发 现在沁恒的说明文档上对文件名的书写有一定的要求:路径名和文件名的格式与DOS 文件名格式相同,但是不含盘符和冒号,左斜杠与右斜杠等效,所有字符必须是大写,不能使用通配符,文件名长度不超过11 个字符,其中主文件名不超过8个字符,扩展名不超过3个字符,如果有扩展名,则用小数点与主文件名隔开。在SD卡的FAT表中,文件名都是以大写字母的 ASCLL码来表示的,如果小写芯片可不会智能识别。在此我有些疑问了,之前没注意到大写这一点,我文件名都用的小写,并且都能正常读写,不知什么原因 了,而且还发现相同的文件名大写和小写CH376会认为是两个文件,所以肯定一个文件名是非正常写入SD卡的FAT 表的,由于公司提供的SD卡是焊死在电路板上的,我也不能从电脑上看看文件名的效果。(对于CH376处理小写的文件名以大写的形式存入SD卡是有例程说 明的)


 


8月23号


调试记录


       对于CH376写数据处理数据长度问题,咨询了沁恒公司,他们的回答是:CH376没有检测写入字符串长度的功能,所以CH376ByteWrite( buf, ReqCount, RealCount )中,ReqCount,即写入的长度,必须是明确的,对于要求写的长度大于实际字符串长度时,多于的长度会以’\0’填充,并且在调用 CH376ByteRead( PUINT8 buf, UINT16 ReqCount, PUINT16 RealCount )时,’\0’是算作数据长度的。


       进行了文件枚举的操作,查找根目录下的JPG文件,在xWriteCH376Cmd( CMD0H_FILE_OPEN );后返回的数据不是USB_INT_DISK_READ(0x1D),而是0xa2,这个代码CH376命令集中并未宏定义,不能很明显的看出错误原 因。


       因为采用的是SPI模式,所以在每次发送完写命令后需要调用xEndCH376Cmd( )函数,使片选无效,结束CH376命令,开始忘了调用该函数导致返回错误码0xa2的。


       在8月19日的调试中遇到这样的问题CH376FileCreatePath(),CH376FileOpenPath()能正常工 作,CH376FileCreate(),CH376FileOpen()不能正常工作其实还是文件名大小写的问题,文件名必须大 写,CH376FileOpen(),文件名写成”/XX.XXX”,CH376FileOpenPath()文件路径写成”/XX/XX.XX”,两 者’/’都不能少。


 


8月24号


调试记录


       写个两个关于查询磁盘剩余容量大小,查询文件大小的函数,准备在创建文件之前,先查询一下剩余容量,若有足够的空间才创建文件,在打开文件之后,查询一下文件的大小,判断依据,剩余空间的大小是否能容纳写入文件数据量的10倍大小(具体倍数应按实际情况确定)。


 


       在查询剩余容量时调用函数CH376DiskQuery( DiskFre ),发现调用该函数,很费时间,查了一下手册,手册上说“查询磁盘剩余空间信息,该子程序在FAT32文件系统的磁盘中调用时最快,在FAT16 文件系统的磁盘中调用时最慢,磁盘容量越大,操作越慢”。当时测试芯片格式化的时候,选择的是格成FAT16文件系统,可以在格式化的时候选择格成FAT32试下


 


       在几个较小数据的文件创建好以后,扇区数一直没变,不知怎么回事歪?


       调了很长时间,发现其实我建好文件以后并没有删除,每次重新编译,下载,运行时 ,建立文件也只是覆盖原有文件,所以读出的剩余扇区数就一直不变了,将建立的文件删除后重新编译,下载 ,运行,可以看到剩余扇区数是有变化的,只是写入的实际数据大小与占用的扇区数是有差别的,这与SD卡的FAT表的结构有关。


 


8月26日


调试记录


测 试了CH376对于SD卡大数据量数据的读写,向SD卡中写入10.1M的数据,发现创建文件写数据时,用先前的 FileCreatAndWrite(ref_u8 *pfilename,ref_u8 *pfiledata,ref_u32 size)和FileOpenAndAddWrite(ref_u8 *pfilename,ref_u8 *pfiledata,ref_u32 size)效率非常低,每次执行FileOpenAndAddWrite()会重复调用FileOpen(),FileLocate()函数。于是修改了 一下程序,按照第一次调用CreatFile();之后重复调用FileWrite()函数,最后关闭文件。经测试10M数据全部写向SD中的文件共花费 了80秒左右。读函数已不能用FileOpenAndRead()因为没有足够的缓存来存储读到的数据,应先调用FileOpen()函数,之后反复调用 FileRead()函数直至读完,在此期间可对缓存区的数据进行处理。经测试将10M的数据全部读完共花费60秒左右(不包括中间对数据处理的时间)


 


CH376调试中需注意的问题及一些说明:


1.    SD卡格式化时,试着格式化成FAT32格式的,在手册上说:“查询磁盘剩余空间信息,该子程序在FAT32文件系统的磁盘中调用时最快,在FAT16 文件系统的磁盘中调用时最慢,磁盘容量越大,操作越慢”。如果要查询磁盘剩余空间,使用FAT16会很慢(调试时,看到打印调试信息明显有停顿 感,FAT32没有测试。)


 


2.    调用总容量函数和剩余容量函数时返回的是扇区数,整成字节时需乘以512.


单次写入字节数尽量是扇区大小512 的倍数,最大字节数不超过 65535。


 


3.    路径名和文件名的格式与DOS 文件名格式相同,但是不含盘符和冒号,左斜杠与右斜杠等效,所有字符必须是大写,不能使用通配符,文件名长度不超过11 个字符,其中主文件名不超过8个字符,扩展名不超过3个字符。CH376FileOpen(),文件名写 成”/XX.XXX”,CH376FileOpenPath()文件路径写成”/XX/XX.XXX”,两者’/’都不能少。


 


4.    CH376没有检测写入字符串长度的功能,所以CH376ByteWrite( buf, ReqCount, RealCount )中,ReqCount,即写入的长度,必须是明确的,对于要求写的长度大于实际字符串长度时,多于的长度会以’\0’填充,并且在调用 CH376ByteRead( PUINT8 buf, UINT16 ReqCount, PUINT16 RealCount )时,’\0’是算作数据长度的。(不能使用strlen()来测试要写入数据缓存区的数据长度)


 


5.对于向文件中写入或者读出大数据量的数据(10M数据),调试输出过程中会有一个较长时间的停顿,属正常情况。


 


6. 对于向SD卡中写数据,一次最大到底应该写多少数据,应该根据实际情况而定,手册上说是最大不超过65535个字节,最好一次写入的字节数是512的倍 数。开始我设定的是65024,即在那个允许的范围内,选择512整数倍的最大数。后来在调试过程中我发现为了能方便进行移位操作(程序中直接用除法,效 率不高)还应满足这个数是2的幂,后来将65024改成了32768,这个数值只能作为一个参考,具体数值应根据能分配的数据缓存大小确定。


 


7.对于从文件读数据,一次能读出的最大字节数也应该根据能分配的数据缓存大小确定,我设定的一次最大能读出512字节的数据。


 


程序的说明:


1.      我主要在ref_main.cpp,ref_usb.cpp,ref_usb.h三个文件中添加的定义及函数,对于添加的函数及函数中的一些关键语句,都有注释。


2.读写缓存的大小,我写了两个宏定义(#define WRITE_MAX_BUF 32768


#define READ_MAX_BUF 512,在ref_usb.h中定义)修改容量时只需修改这两个数值。


3.写大量数据时,应先调用FileOpenPath(()函数,文件打开成功之后,反复调用FileWrite()函数,直至将所要写入的数据写完,最后调用FileClose(TRUE)函数,关闭文件并更新文件长度。


4.读文件中的数据时,应先调用CreatFile()函数,成功之后,反复调用FileRead()函数,直至将文件中的数据读完,最后调用FileClose(FALSE)函数,关闭文件不更新文件长度。

  评论这张
 
阅读(425)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018