我说明书里写的支持98%以上的U盘,这是官方的说法啊,这下可好,客户拿这个朝我们开刀。其中一个是KINGSTON的1G的。现象就是:能认U盘,但初始化时读数据不来中断,死机。我把读中断的程序改了一下不是死循环,不死机,但读不出数据。
512M的倒没见过什么问题,希望相关人能给个说法
如果你是使用我们库操作U盘的话,那么建议你到我们公司网站上面去更新下库和头文件应该这种型号的U盘应该就支持了,如果不是使用库的话而是直接操作U盘物理扇区的话,那么可能需要看下你的初始化程序。
unsigned char InitDisk(void) { unsigned char FFDD=0; //是否成功标志位 0不成功,1成功 unsigned char stat; unsigned char i,j; WriteCmd(CMD_GET_STATUS); stat = ReadData(); if(stat == USB_INT_DISCONNECT) { } //USB设备断开,提示插入U盘error_handle1(); WriteCmd(CMD_DISK_INIT); //初始化USB存储器 stat = GetInt(); if(stat != USB_INT_SUCCESS) //初始化不成功 { return(0); } for(i=0;i<200;i++) //读取容量 { WriteCmd(CMD_DISK_SIZE); //获取USB存储器容量 stat = GetInt(); if(stat == USB_INT_SUCCESS) {FFDD=1; break; } //读取成功则退出 } if(FFDD==1) { WriteCmd(CMD_RD_USB_DATA); i = ReadData(); for(; i > 0; i--) ReadData(); //容量数据,参看数据手册5-6 } return(FFDD); }
U盘初始化程序,帮着看看吧,好象是你们库里面的
void CH375_INIT(void) //CH375相关的初始化 { unsigned char i,c; PORTC |= RST_CH; //复位CH375 delay_ms(400); PORTC &= ~RST_CH; delay_ms(400); WriteCmd(CMD_RESET_ALL); //执行硬件复位 ///////////// delay_ms(200); ///////////// WriteCmd(CMD_CHECK_EXIST); //工作测试,送5A正确应该读到A5 WriteData(0x57); i = ReadData(); if(i != 0xA8) //工作不正常 { error_handle2(); } //如初始化未成功,void error_handle2(void) WriteCmd(CMD_SET_USB_MODE); // 初始化CH375,设置USB工作模式 WriteData(6); // 模式代码,自动检测USB设备连接 6 }
CH375的初始化
你在哪一步出问题了
哪一步? 怎么官方不给个说法啊? 要不就干脆说CH375不支持,这样我也好跟客户交代
按照如果你操作物理扇区的话,我们可以提供给你例子程序,如果需要的话,可以直接发送E-MAIL到tech@wch.cn,我们会即时给你回例子程序的。同时你也需要看下你的程序停在什么地方了,这个并不是我们375芯片支持不支持的问题,这个估计和你软件上面有关系,我们需要你的程序停在什么地方。然后根据你的现象来做相应的处理操作
程序死在等待中断那里了,已确认。 读数据不来中断
那要是这样的话,你可以在中断上面加超时,当超时完之后,你可以将芯片复位在进行初始化。
比较老点的U盘,可能去年生产的吧,包括一些特别老的MP3,插上去都能认,没问题,就是这些新出的U盘,特别是牌子的,大U盘,一般都会出问题,搞得客户一直给我们打电话询问,因为我们的说明书上是照你们官方的说法:支持市面上90%以上的U盘。结果其中一个客户买了4个U盘,不同牌子的,全都不支持。这些都是高速U盘,我觉得可能跟这个有关系。
我试过加超时,用10000个指令周期等待中断来,无中断则继续进行没返回错误。这样可以不死机,但读不出数据。
这个问题我也不想解决了,打算在网站上发布一条公告,告诉客户买差一点的U盘就可以了。
你可以拿下面的程序去更新下看可以不可以操作U盘:
/* CH375作为USB主机接口的程序示例 */
/* MCS-51单片机C语言的示例程序, U盘数据读写 */
#include #include #include
#define MAX_SECTOR_SIZE 4096 /* 以512字节每扇区为主,部分有2K字节每扇区,最大为4K字节 */
/* 定义CH375命令代码及返回状态 */ #include "CH375INC.H" /* CH375特性 */ #define CH375_BLOCK_SIZE 64 /* CH375 maximum data block size */
/* 以下定义适用于MCS-51单片机,其它单片机参照修改,为了提供C语言的速度需要对本程序进行优化 */ #include unsigned char volatile xdata CH375_CMD_PORT _at_ 0xBDF1; /* CH375命令端口的I/O地址 */ unsigned char volatile xdata CH375_DAT_PORT _at_ 0xBCF0; /* CH375数据端口的I/O地址 */ unsigned char xdata DATA_BUFFER[ MAX_SECTOR_SIZE ] _at_ 0x0000; /* 外部RAM数据缓冲区的起始地址,长度不少于一次读写的数据长度 */ sbit CH375_INT_WIRE = 0xB0^2; /* P3.2, INT0, 连接CH375的INT#引脚,用于查询中断状态 */
unsigned short BytePerSector; /* 每扇区字节数,扇区大小 */ unsigned char BlockPerSector; /* 每扇区块数,指CH375读写时的块 BlockPerSector=BytePerSector/CH375_BLOCK_SIZE */ #define UINT8 unsigned char unsigned char CH375IntStatus; unsigned short SectorSize; #define USB_BO_CBW_SIZE 0x1f #define SPC_CMD_READ10 0x28 #define SPC_CMD_WRITE10 0x2a
/* 在P1.4连接一个LED用于监控演示程序的进度,低电平LED亮,当U盘插入后亮 */ sbit P1_4 = P1^4; #define LED_OUT_ACT( ) { P1_4 = 0; } /* P1.4 低电平驱动LED显示 */ #define LED_OUT_INACT( ) { P1_4 = 1; } /* P1.4 低电平驱动LED显示 */
/* 延时2微秒,不精确 */ void delay2us( ) { unsigned char i; for ( i = 2; i != 0; i -- ); }
/* 延时1微秒,不精确 */ void delay1us( ) { unsigned char i; for ( i = 1; i != 0; i -- ); }
/* 延时毫秒,不精确 */ void mDelaymS( unsigned char cnt ) { unsigned char i, c; while ( cnt -- ) { for ( i = 250; i != 0; i -- ) c+=3; } }
/* 基本操作 */
void CH375_WR_CMD_PORT( unsigned char cmd ) { /* 向CH375的命令端口写入命令,周期不小于4uS,如果单片机较快则延时 */ delay2us(); CH375_CMD_PORT=cmd; delay2us(); }
void CH375_WR_DAT_PORT( unsigned char dat ) { /* 向CH375的数据端口写入数据,周期不小于1.5uS,如果单片机较快则延时 */ CH375_DAT_PORT=dat; delay1us(); /* 因为MCS51单片机较慢所以实际上无需延时 */ }
unsigned char CH375_RD_DAT_PORT() { /* 从CH375的数据端口读出数据,周期不小于1.5uS,如果单片机较快则延时 */ delay1us(); /* 因为MCS51单片机较慢所以实际上无需延时 */ return( CH375_DAT_PORT ); }
void xQueryInterrupt( void ) /* 查询CH375中断并更新中断状态 */ { unsigned char i; for ( i = 0xffff; CH375_INT_WIRE != 0; i -- ) { /* 如果CH375的中断引脚输出高电平则等待 */ if ( CH375_INT_WIRE == 0 ) break; if ( CH375_INT_WIRE == 0 ) break; if ( CH375_INT_WIRE == 0 ) break; if ( ( i >> 8 ) == 0 ) { if ( i == 0 ) { CH375_CMD_PORT = CMD_RESET_ALL; } else if ( ( i & 0xFF ) == 0xFF ) CH375_CMD_PORT = CMD_ABORT_NAK; } } CH375_CMD_PORT = CMD_GET_STATUS; /* 获取当前中断状态 */ delay1us();delay1us(); CH375IntStatus = CH375_DAT_PORT; /* 获取中断状态 */ }
/* 发出命令及一个数据并等待状态,成功返回ERR_SUCCESS */ static void Write_Cmd_Port( UINT8 iDat, UINT8 iCmd ) { CH375_WR_CMD_PORT( iCmd ); CH375IntStatus = 0; /* 清操作完成的中断状态 */ CH375_WR_DAT_PORT( iDat ); xQueryInterrupt( ); /* 查询方式,查询中断状态 */ if ( CH375IntStatus == 0x00 ) CH375IntStatus = 0x10; /* 意外的USB错误 */ else if ( CH375IntStatus == USB_INT_SUCCESS ) CH375IntStatus = 0x00; /* 操作成功 */ }
/* 等待CH375中断并获取状态 */ unsigned char mWaitInterrupt() { /* 主机端等待操作完成, 返回操作状态 */ while( CH375_INT_WIRE ); /* 查询等待CH375操作完成中断(INT#低电平) */ CH375_WR_CMD_PORT( CMD_GET_STATUS ); /* 产生操作完成中断, 获取中断状态 */ return( CH375_RD_DAT_PORT( ) ); }
/* 设置CH375为USB主机方式 */ unsigned char mCH375Init( ) { unsigned char i; #ifdef TEST_CH375_PORT unsigned char c; CH375_WR_CMD_PORT( CMD_CHECK_EXIST ); /* 测试工作状态 */ CH375_WR_DAT_PORT( 0x55 ); /* 测试数据 */ c = CH375_RD_DAT_PORT( ); /* 返回数据应该是测试数据取反 */ if ( c != 0xaa ) { /* CH375出错 */ for ( i = 100; i != 0; i -- ) { /* 强制数据同步 */ CH375_WR_CMD_PORT( CMD_RESET_ALL ); /* CH375执行硬件复位 */ c = CH375_RD_DAT_PORT( ); /* 延时 */ } mDelaymS( 50 ); /* 延时至少30mS */ } #endif CH375_WR_CMD_PORT( CMD_SET_USB_MODE ); /* 设置USB工作模式 */ CH375_WR_DAT_PORT( 6 ); /* 模式代码,自动检测USB设备连接 */ for ( i = 0xff; i != 0; i -- ) /* 等待操作成功,通常需要等待10uS-20uS */ if ( CH375_RD_DAT_PORT( ) == CMD_RET_SUCCESS ) break; /* 操作成功 */ if ( i != 0 ) return( 0 ); /* 操作成功 */ else return( 0xff ); /* CH375出错,例如芯片型号错或者处于串口方式或者不支持 */ }
/* 执行基于BulkOnly协议的扇区读写命令 */ /* 入口: IsRead 非0是读操作,否则是写操作 */ /* SecCount 读写扇区数 */ unsigned char mBocCbwOutStart( unsigned char IsRead, unsigned char SecCount, unsigned long SecLba ) { unsigned char TempVar,i; CH375_WR_CMD_PORT( CMD_READ_REG ); CH375_WR_DAT_PORT( VAR_UDISK_DSK_LUN ); TempVar = CH375_RD_DAT_PORT( ); CH375_WR_CMD_PORT( CMD_WR_USB_DATA7 ); /* 向USB端点2的发送缓冲区写入数据块 */ CH375IntStatus = 0; /* 清操作完成的中断状态 */ CH375_WR_DAT_PORT( USB_BO_CBW_SIZE ); /* 后续数据的长度 */ CH375_WR_DAT_PORT( 'U' ); CH375_WR_DAT_PORT( 'S' ); CH375_WR_DAT_PORT( 'B' ); CH375_WR_DAT_PORT( 'C' ); CH375_WR_DAT_PORT( 0x03 ); CH375_WR_DAT_PORT( 0x07 ); CH375_WR_DAT_PORT( 0x05 ); CH375_WR_DAT_PORT( 0x0A ); CH375_WR_DAT_PORT( 0x00 ); /* 数据传输长度 */ CH375_WR_DAT_PORT( (unsigned char)( SecCount * (unsigned short)( SectorSize >> 8 ) ) ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( IsRead ? 0x80 : 0x00 ); /* 传输方向等标志 */ CH375_WR_DAT_PORT( TempVar ); /* 当前逻辑单元号 */ CH375_WR_DAT_PORT( 0x0A ); /* 命令块长度 */ CH375_WR_DAT_PORT( IsRead ? SPC_CMD_READ10 : SPC_CMD_WRITE10 ); /* 命令码 */ CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( SecLba >> 24 ); CH375_WR_DAT_PORT( SecLba >> 16 ); CH375_WR_DAT_PORT( SecLba >> 8 ); CH375_WR_DAT_PORT( SecLba ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( SecCount ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( 0x00 ); CH375_WR_DAT_PORT( 0x00 ); /* UFI操作 */ CH375_WR_CMD_PORT( CMD_READ_REG ); CH375_WR_DAT_PORT( VAR_UDISK_TOGGLE ); TempVar = CH375_RD_DAT_PORT( ); CH375_WR_CMD_PORT( CMD_WRITE_REG ); CH375_WR_DAT_PORT( SFR_USB_H_ENDP ); CH375_WR_DAT_PORT( TempVar ); CH375_WR_CMD_PORT( CMD_READ_REG ); CH375_WR_DAT_PORT( VAR_UDISK_BULK_OUT ); i = CH375_RD_DAT_PORT( ); Write_Cmd_Port( i, CMD_ISSUE_TOKEN ); /* 获取USB盘的OUT端点,向USB盘的OUT端点输出CBW */ CH375_WR_CMD_PORT( CMD_WRITE_REG ); CH375_WR_DAT_PORT( VAR_UDISK_TOGGLE ); CH375_WR_DAT_PORT( TempVar ^ 0x40 ); if ( CH375IntStatus != 0x00 ) { /* 发送CBW失败,复位USB磁盘 */ TempVar = CH375IntStatus; CH375_WR_CMD_PORT( CMD_READ_REG ); CH375_WR_DAT_PORT( VAR_UDISK_BULK_IN ); i = CH375_RD_DAT_PORT( )>>4 | 0x80; Write_Cmd_Port( i | 0X80, CMD_CLR_STALL ); /* 清除IN端点错误 */ CH375_WR_CMD_PORT( CMD_READ_REG ); CH375_WR_DAT_PORT( VAR_UDISK_BULK_OUT ); i = CH375_RD_DAT_PORT( )>>4 | 0x80; Write_Cmd_Port( i, CMD_CLR_STALL ); /* 清除OUT端点错误 */ return( CH375IntStatus = TempVar ); /* 返回原错误码 */ } CH375_WR_CMD_PORT( CMD_WRITE_REG ); CH375_WR_DAT_PORT( VAR_UDISK_SECTORS ); CH375_WR_DAT_PORT( SecCount * ( SectorSize >> 9 ) ); CH375_WR_CMD_PORT( CMD_WRITE_REG ); CH375_WR_DAT_PORT( VAR_UDISK_PKT_CNT ); CH375_WR_DAT_PORT( 0x08 ); CH375_WR_CMD_PORT( CMD_READ_REG ); CH375_WR_DAT_PORT( VAR_SYS_FLAG ); i = CH375_RD_DAT_PORT( ) | BIT_USB_DISK_CMD; CH375_WR_CMD_PORT( CMD_WRITE_REG ); CH375_WR_DAT_PORT( VAR_SYS_FLAG );