基于CH376的SD卡调试记录(基于NIOS II)
一.调试计划:
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=””。向文件中写入数据使用函数CH376ByteWrite( pfiledata, size, NULL )。
字符串长度和字节打开文件读取数据采用FileOpenAndRead(ref_u8 *pfilename,ref_u8 *pbuffer,ref_u8 size)函数,其中文件名格式filename=””,即只能打开当前目录下的文件打开文件读取数据时
出现问题:a.有时显示文件没到,b.有时文件打开成功,但返回数据长度不正确,察看数据缓冲区发现数据已丢失。
下午调试记录
先前已将文件建立好,试着注释掉创建文件并向文件中写入数据那段函数之后,能成功打开文件并正确读取数据。(注:其实后来也不知道什么原因能读出来的,当时文件名是小写,所以本身操作是不合规定的。)
采用结构体数组的形式定义5组文件名,5组数据,创建5个文件,并向创建好的文件中写入定义好的数据,5组数据分别为10字节,15字节,20字节,25字节,30字节,包含字母与数字。先执行FileCreatAndWrite()函数,成功创建5个文件并分别向其中写入相应数据,注释掉该部分内容,执行FileOpenAndRead()函数,成功打开刚建的5个文件,正确返回相应的字节数。
将两部分内容连起来,既先调用FileCreatAndWrite()函数接着调用FileOpenAndRead()函数,第一部分能成功进行,提示“创建并数据写入成功”,但打开文件时提示“文件读取失败”,返回代码0x42(未到文件提示错误),之间需要延时?延时2秒,还是那错误……
后来将创建文件的函数改成CH376FileCreatePath(),打开文件的函数改成 CH376FileOpenPath(),既支持多路径下的文件操作后,上述问题解决,注意此时字符串格式为”/”。(其实两个函数的区别无非就是文件名关键字的提取,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,这个数值只能作为一个参考,具体数值应根据能分配的数据缓存大小确定。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论