上次用字节方式写文件成功了。但现在要记录比较大的文件,要求速度,只好用突发方式。在一个地方卡住了,就是在用WR_HOST_DATA写完64个字节后,返回操作失败。研究很久不知道错在哪里,写信号的已经降到只有100K左右了,绝对在数据手册规定的时序范围内。U盘也换过,FAT32和FAT格式也都试过,都不行。 贴上实际采样的时序,请高手分析一下。 请点击图片,显示原始大小。
补充说明一下: 虽然操作失败,但在U盘上也有一个文件,文件名是对的,但内容不对。 原来是想存512个ASCII为“2F”(即"\"),结果里面总是只有一个字节的内容,而且每次还不一样,有时是"2",有时是".",有时是" "(空格)。 可以确认写完WR_HOST_DATA后,写了一个0x40,然后64个0x2F(数过好几遍)。
一般写多少数据就会出现这种情况? 如果文件写完之后没有更新文件长度,默认的文件长度是1个字节,这个字节是一个随机数。
因为是SEC_WRITE,所以一次写64个字节,而我第一次写完64个字节就得到了1F。 明白了,如果读到1F,我的程序就挂起了,没有执行后续CLOSE_FILE(包括更新文件长度)操作,所以文件长度为1,并且是随机数。 用WINHEX看了自己试过的两个U盘,都是512 bytes/sector。量了一下USB引脚电压,4.89V与3.27V。应该不会有什么问题吧,字节操作都正常的。
如果字节写是正常 那就不应该是硬件问题, 扇区写做好参考官方提供的例程,下载CH376EVT.ZIP 参考CH376EVT\EXAM\EXAM8
完全是按那个例子来的。
for ( err = 0; err != 3; ++ err ) { /* 出错重试 */ xWriteCH376Cmd( CMD5H_DISK_WRITE ); /* 向USB存储器写扇区 */ xWriteCH376Data( (UINT8)iLbaStart ); /* LBA的最低8位 */ xWriteCH376Data( (UINT8)( (UINT16)iLbaStart >> 8 ) ); xWriteCH376Data( (UINT8)( iLbaStart >> 16 ) ); xWriteCH376Data( (UINT8)( iLbaStart >> 24 ) ); /* LBA的最高8位 */ xWriteCH376Data( iSectorCount ); /* 扇区数 */ xEndCH376Cmd( ); for ( mBlockCount = iSectorCount * DEF_SECTOR_SIZE / CH376_DAT_BLOCK_LEN; mBlockCount != 0; -- mBlockCount ) { /* 数据块计数 */ s = Wait376Interrupt( ); /* 等待中断并获取状态 */ if ( s == USB_INT_DISK_WRITE ) { /* USB存储器写数据块,请求数据写入 */ CH376WriteHostBlock( buf, CH376_DAT_BLOCK_LEN ); /* 向USB主机端点的发送缓冲区写入数据块 */ xWriteCH376Cmd( CMD0H_DISK_WR_GO ); /* 继续执行USB存储器的写操作 */ xEndCH376Cmd( ); buf += CH376_DAT_BLOCK_LEN; } else break; /* 返回错误状态 */ } if ( mBlockCount == 0 ) { s = Wait376Interrupt( ); /* 等待中断并获取状态 */ if ( s == USB_INT_SUCCESS ) return( USB_INT_SUCCESS ); /* 操作成功 */ } if ( s == USB_INT_DISCONNECT ) return( s ); /* U盘被移除 */ CH376DiskReqSense( ); /* 检查USB存储器错误 */ }
分析下来,当执行完DISK_WRITE(0x56),并输入四字节LBA和扇区数后,中断得到0x1E,即通知FPGA开始写64个字节的内容,问题出在写完64个字节后,返回的错误代码是0x1F,存储设备操作失败,那应该是写U盘失败。就是在第二次执行红色的代码时判断条件结果为假。正常情况应该还是返回0x1E,让我写完后面的内容,一次扇区至少要写512字节吧。
有新发现。 虽然扇区只写了64个字节,并且返回错误信息,但我将软件改成出错强制关闭文件并且更新文件长度后, 得到了一个4096字节的文件,内容很丰富,但没有一个是我想要的。文件长度是对的,因为我的试验程序写了8个SECTOR,共8*512=4096。 虽然是乱码,但里面有些有趣的东西,比如有SETUP.EXE、config.ini、readme.txt等字符。这个U盘是完全格式化后再接CH376上的,应该是干干净净的,我也只是在根目录下存个N.TXT一个文件,这些内容既然不是FPGA写进去的,那么究竟是哪里来的呢?
计算机格式化U盘,并不是把所有的扇区都清零,而是在文件的目录项中作了一个标志 表示该文件被删除。实际上文件的内容还在,计算机上看不到而已,所有即使U盘被格式化了 数据也有可能会被恢复。 这种修改文件长度的方法是不对的。 只会把一些无效的数据包含在文件中,参考下面的代码修改一下 LPC2214下面的例程。UploadImages/20111715305665.rar
另外你可以再次测试一下你的程序在字节模式下是否仍然可以。如果可以的话,你移植一下扇区的读写函数即可,应该问题不大。
那个ARM的文件我也已经参考过了,与单片机的几乎是一样的。 现在问题的焦点在于:为了什么用WR_HOST_DATA命令将64个字节(固定为0x30,即字符“0”)写到主机端点后,没有成功写到存储设备即U盘上。 十分感谢_study_的帮助,我把FPGA捉到的完整的实际时序图传上来,有劳您或其他大侠分析分析。这关冲过去,可能后面就一顺到底了。 UploadImages/20111715533920.rar 说明:图中数据总线=FF表示让总线高阻,准备接收数据,而非输出数据0xFF。原理同单片机IO=1时方能读入状态一样。
回复:红桃六 我试了一下,字节模式下仍然OK。 我也是对照着EXAM8,一步步移植过来的,当初字节模式非常顺利。 现在扇区模式前面也很顺序,就是卡在了上面说的那一步,反复检查得不到结果。
把代码发过来看看,A0信号线默认为低电平,写完命令之后把A0拉低
这个问题还真有点难度。 根据_study_的建议,A0信号改为平时常为低,只在发命令时变高,原来我是平时为高,读写数据是为低。但改过来后结果一样。
自己又进了一步,当得到1F(存储设备操作失败)的错误码后,执行5A命令(检查存储器错误),CH376中断后告诉我指令执行成功,我再执行CMD_RD_USB_DATA0,CH376告诉我有18个字节的错误代码,用FPGA抓了: 0xF0,0x00,0x05,0x00,0x00,0x00,0x00,0x0A,0x00,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00 数据手册上没有找到错误代码的说明,还请高手帮忙分析。 源码是VHDL的,不过很容易读,用了最笨但最可靠的方法,就是用状态机生成各种操作时序。全部通过后我会做优化工作,让程序更符合规范的。 附件中还有实际捉到的时序图。 UploadImages/20111811361294.rar
另外,在一开始,我没有用CH376DiskConnect( )来检查U盘是否连接,因为开机时U盘一定是插好的,另外,从ACT#脚上接的LED应该也可以看出是否正常连接。同时也没有检查U盘的剩余空间。原来字节模式我也都没有检查,应该没有关系吧。我仔细分析了一下,与EXAM8就这一点区别了。 还有一个发现就是文件新建后,执行扇区写命令时,CH376会自动分配起始扇区号。但这个扇区号并不对应实际U盘上文件的起始扇区号,而是后移了64个扇区。我强制把数据写到实际文件起始的扇区位置,还是返回1F。
CMD0H_DISK_MOUNT(0x31)命令有没有测试通过? 另外对于高速MCU来说,命令式数据之间要有2-4uS的延时,数据和数据之间也要有1-2us的延时
0X31过的,一直到写入64字节命令都是全部正常通过的。延时时序一定能保证。 翻了一天的老贴子,有所发现。并不是我一个人会遇到这个问题。但他们大部分发了几次后再出现错误的,0x1F,是所有用使用CH376工程师的恶梦之一。 有的说换U盘就好了,可是现在我手头只有两个U盘,一个是最普遍的“KINGSTON(4G)”,还有个“SSK(2G)”。两个都可以进行字节操作,如果红桃的说法正确,那么肯定也支持扇区。而且CH376对U盘有90%的支持率,我想我的运气不会那么差吧。两个正好都是那个十分之一。 老贴子中有一篇是说一定要先获取U盘剩余空间后再进行操作。不知道是不是硬件规定。今天修改程序再看一下。
读出了总扇区数和剩余扇区数,与WINHEX得到结果完全一样。FAT类型为03,数据手册上查不到,应该是FAT32吧。 但是结果还是一样。第一个64字节就写不进去。 下一步,自己放个文件,看看扇区读能不能操作。 其实关键是我在第12楼得到的那串错误代码,我来联系一下WCH的技术支持,看看能不能有所发现。