http://group.ednchina.com/1737/22909.aspx
1. 元器件
CYPRESS 68013A :支持USB 2.0 协议,带增强型8051 单片机,时钟频率48Mhz 。支持串口通讯。
2. 文档
cy7c68013.pdf |
68013 外设手册 |
cy7c68013_5.pdf |
68013 外设手册 |
CY3684_A_SCH.PDF |
68013A 外围电路图 |
FX2 TechRefManual.pdf |
EZUSB-FX2 技术手册 |
fx2_to_fx2lp.pdf |
FX2 和FX2LP 的区别 |
CYAPI.PDF |
CYAPI 手册 高级类库 |
CYUSB.PDF |
CYUSB 手册 底层API |
|
|
3. 开发环境
3.1 Keil C 7.0 编译器
3.2 C++ Builder 6.0
3.3 VC++ 6.0
3.4 EEPROM 烧写器
3.5 68013A 的开发包(含CYPRESS CONSOLE 、CYUSB.SYS 、例程等)
3.6 BUS HOUND 5.0
4. 开发流程
4.1 硬件程序编写
1 )根据CYPRESS 的示例程序建立工程框架,一般由FW.C PERIPH.C 和定义寄存器的几个头文件组成。
2 )FW.C 负责了设备连接、重枚举、设备初始化等过程
3 )PERIPH.C 负责响应各种中断事件。
4 )dscr.a51 文件定义了USB 设备握手时需要的各种描述符
5 )FX2REGS.H 定义了USB 中所有的寄存器
6 )FX2.H 主要定义了各种二级中断向量和描述符的数据结构
7 )编译后的二进制代码和工程同名,扩展名为HEX 。
8) 相应的头文件和类库在KEIL C 的lib 和inc 文件夹内,需在项目设置中设置路径。
4.2 硬件程序烧录
1) 因为本产品要求将二进制代码和硬件PID/VID 烧录在EEPROM ,而不是使用CYPRESS 推荐的在线下载方式,所以外部采用了8K 的EEPROM 。上电后68013A 会将EEPROM 中的数据和程序加载到RAM 中运行。
2) HEX 文件只是68013A 上8051 的程序代码,还要加上PID/VID 等信息才能正确运行,CYPRESS 在开发包中提供了HEX2BIN.EXE 这个工具,可以根据HEX 生成完备的IIC 文件,将此文件烧录到EEPROM 上即可。
3) HEX2BIN.EXE 的使用方法如下:
将XXX.HEX 文件拷贝到HEX2BIN.EXE 所在目录,打开CMD ,按如下格式输入:
hex2bix -i -o xxx.iic xxx.hex -f 0xC2 -v 0x1234 -p 0x1234
-i 表示输出文件,也就是IIC 文件
-o 表示输入文件,也就是HEX 文件
-f 表示68013A 发送PID/VID 的方式,这里为C0 ,即从EEPROM 上读取。
-v 表示VID 的BCD 码,开发阶段使用1234
-p 表示PID 的BCD 码,开发阶段使用1234
4) 将生成的IIC 文件用烧写器烧录到EEPROM 上,本项目使用的是深圳思泰佳电子公司的NSP 通用烧写器,此烧写器不支持IIC 类型,选择BIN 类型可替代。
4.3 驱动的识别
1) 将EEPROM 连到68013A 上后,接上USB 线,上电。计算机提示找到新硬件,要求安装驱动。
2) CYPRESS 针对68013A 提供了全新的驱动程序CYUSB.SYS 。这个驱动使用了新的API ,所以上位机的编写上和旧的方式完全不同。底层的IOCTL 控制字的定义也完全不同,详见CYAPI.PDF 和CYUSB.PDF 。
3) 安装驱动之前,必须先根据VID/PID 正确编辑CYUSB.INF 文件,在文件中添加自己的PID/VID 代码和设备描述,连接设备时,将根据硬件上的PID/VID 查找INF 文件中对应的驱动,如果找不到,在设备管理器中将显示“68013 EEPROM MISSING” 的字样。
4) 详细的INF 配置方法参考CYUSB.PDF PART1/PART2/PART3 。这里不在赘述。
5) 安装驱动时候找到修改好的CYUSB.INF 文件,驱动将被正确安装,此时设备可以正常使用。
4.4 测试过程
1) 被正确识别的设备可以在CYPRESS CONSOLE 上看到设备信息。如图:
2) CYPRESS CONSOLE 的具体使用方法请参考CyConsole.chm 。
3) 要注意的是,除EP0/EP1 外,当其他端点Max Pkt Size 大小为64 字节时,表示工作在USB 1.1 模式,有可能是软件的原因,也有可能是外围上拉电阻的问题。开发中要特别注意。
5. 推荐开发流程
5.1 看本介绍USB 2.0 协议的书,对USB 2.0 协议有所了解。推荐《USB 2.0 原理与工程开发》
5.2 看CYUSB.PDF 文档。了解驱动安装方法。
5.3 看KEIL C51 的书籍,熟悉C51 的编程方法,熟悉KEIL C 编程环境。
5.4 看CYPRESS 提供的例程,了解68013A 编程框架。推荐《EZ-USB 2100 系列单片机原理、编程及应用》(基本框架类似,部分寄存器定义不同)。
5.5 对照USB 2.0 协议,编写dscr.a51 文件,配置各种描述符。
5.6 结合FX2 TechRefManual.pdf ,研读FW.C 、PERIPH.C 、FX2REGS.H 、FX2.H ,了解寄存器的定义。
5.7 根据系统需求编写响应代码,有开发板时,根据开发版上的LED 来测试程序正确与否。
5.8 根据CYAPI.PDF CYUSB.PDF 编写上位机通讯程序。
同步读取数据方法 XferData();
异步读取数据方法 BeginDataXfer()/WaitForXfer()/FinishDataXfer();
5.9 调试程序。
5.10 编写其他8051 上的程序,并继续调试。
6. 发布时应提供的文件
1) CYUSB.SYS
2) CYUSB.INF
3)XXX .IIC
7. 重点讲解
7.1 如何理解CYPRESS 68013A 程序框架
CYPRESS 提供了非常好的程序框架,免去了用户自己编写一些通用性比较强、模式化的程序(如果不提供,很少有人能写出如此高效,结构紧凑的程序,实际上此框架和68013A 内部结构关系密切,一般人也没有足够的内部资料也不可能写出来)。在框架的基础上,用户只需在相应的地方写相应的代码即可完成USB 工作。
一般来说框架可以分成3 个部分。
1) 描述符文件。例如dscr.a51 文件,里面定义了枚举设备的时候要用的各种描述符信息,这部分用户需要根据实际的情况自己编写。我写的时候发现一个最大的问题就是各种书籍协议版本不同,翻译质量不同,同一字段的意义表述不同,容易让人产生困惑。例如USB 1.1/2.0/2.13 对设备类型的子类定义都不完全相同,所以写的时候最好几种文档对比起来写。由于USB 官方网站的文档中字段解释过于专业化,所以对USB 不是很熟悉的人比较难以理解其真正含义。所以要多参考不同的书籍,某种程度上降低了开发速度,但对第一次做USB 开发的人来说,这也是值得的。
2) 固件文件,例如FW.C 文件,这是硬件程序的函数入口。主要有以下这些方法:
void SetupCommand(void); // 握手命令处理
void TD_Init(void); // 初始化,完成配置,启动时调用一次
void TD_Poll(void); // 用户处理程序,循环调用
void IO_Init(void); //8051 IO 初始化
void REG_Init(void); //8051 寄存器初始化
BOOL TD_Suspend(void); // 挂起处理
BOOL TD_Resume(void); // 唤醒处理
// 以下为各种描述符的获取和设置函数,重枚举时自动调用
BOOL DR_GetDescriptor(void);
BOOL DR_SetConfiguration(void);
BOOL DR_GetConfiguration(void);
BOOL DR_SetInteRFace(void);
BOOL DR_GetInterface(void);
BOOL DR_GetStatus(void);
BOOL DR_ClearFeature(void);
BOOL DR_SetFeature(void);
BOOL DR_VendorCmnd(void);
3) 功能文件,处理各种中断。例如PERIPH.C 文件。8051 一般默认只有四个中断,这显然不够USB 使用,所以CYPRESS 引入了自动向量的概念,相当于软中断,大大扩展了现有的中断数量。主要的中断有:
void ISR_Sudav(void) interrupt 0 // 收到setup 包
void ISR_Sutok(void) interrupt 0 // 收到SETUP 令牌
void ISR_Sof(void) interrupt 0 // 收到起始帧
void ISR_Ures(void) interrupt 0 // 收到RESET
void ISR_Susp(void) interrupt 0 // 收到挂起信息
void ISR_Highspeed(void) interrupt 0 // 高速模式
void ISR_Ep0ack(void) interrupt 0 // 正常响应ACK
void ISR_Stub(void) interrupt 0
void ISR_Ep0in(void) interrupt 0
void ISR_Ep0out(void) interrupt 0
void ISR_Ep1in(void) interrupt 0
void ISR_Ep1out(void) interrupt 0 //EP1 输入中断
void ISR_Ep2inout(void) interrupt 0 //EP2 中断
void ISR_Ep4inout(void) interrupt 0
void ISR_Ep6inout(void) interrupt 0
void ISR_Ep8inout(void) interrupt 0
void ISR_Ibn(void) interrupt 0
void ISR_Ep0pingnak(void) interrupt 0
void ISR_Ep1pingnak(void) interrupt 0
void ISR_Ep2pingnak(void) interrupt 0
void ISR_Ep4pingnak(void) interrupt 0
void ISR_Ep6pingnak(void) interrupt 0
void ISR_Ep8pingnak(void) interrupt 0
void ISR_Errorlimit(void) interrupt 0
void ISR_Ep2piderror(void) interrupt 0
void ISR_Ep4piderror(void) interrupt 0
void ISR_Ep6piderror(void) interrupt 0
void ISR_Ep8piderror(void) interrupt 0
void ISR_Ep2pflag(void) interrupt 0
void ISR_Ep4pflag(void) interrupt 0
void ISR_Ep6pflag(void) interrupt 0
void ISR_Ep8pflag(void) interrupt 0
void ISR_Ep2eflag(void) interrupt 0
void ISR_Ep4eflag(void) interrupt 0
void ISR_Ep6eflag(void) interrupt 0
void ISR_Ep8eflag(void) interrupt 0
void ISR_Ep2fflag(void) interrupt 0
void ISR_Ep4fflag(void) interrupt 0
void ISR_Ep6fflag(void) interrupt 0
void ISR_Ep8fflag(void) interrupt 0
void ISR_GpifComplete(void) interrupt 0
void ISR_GpifWaveform(void) interrupt 0
特别是对于接受数据,一般都在中断中完成相应处理,“中断中适合进行少量简短的操作,不适合进行复杂操作”,这句话在此依然有效。如果要进行复杂的操作可以在TD_POLL() 中进行(多数操作都是在这个函数中完成的)。
另外非常重要的一点是,中断程序的结尾应该让中断复位,允许下一次中断,有些端点的计数器也要清零并允许接受新的中断请求。例如:
EP1OUTBC = 0; // 清空计数
EZUSB_IRQ_CLEAR(); //USB 中断复位
EPIRQ = 0x08; // 允许EP1 中断请求
7.2 68013A 端点寄存器介绍
68013A 内部的寄存器约有300 个上下,一次都记住是不可能的,而且每个寄存器都有8 个位,也就是说一共有2000 多个可以配置的位,一次都理解掌握这些位的含义也是不可能的,所幸地是开发中并不会用到所有的寄存器,但是依然强烈建议把FX2REGS.H 和FX2.H 走读一边,这就像读书一样,没有学会识字,再看都是天书。结合FX2 TechRefManual.pdf 走读这些寄存器大约需要一到两天时间,这点时间投入还是值得的。
在通讯过程中,打交道最多的是各种端点寄存器,掌握好这些寄存器地使用对提升开发效率是很有帮助。值得特别关注的寄存器和配置位如下:
Rwuen 、REVCTL 、EP1OUTCFG 、EP1INCFG 、EP2CFG 、EP4CFG 、EP6CFG 、EP8CFG 、EP2FIFOCFG 、EP4FIFOCFG 、EP6FIFOCFG 、EP8FIFOCFG 、FIFORESET 、EPIRQ 、EPIE 、EP1OUTBC 、APTR1H 、APTR1L 、EXTAUTODAT1 、AUTOPTRH2 、AUTOPTRL2 、EXTAUTODAT2 、EP2BCH 、EP2BCL
其中有些寄存器的设置需要连续设置多次,看似重复了,其实不然,这和设置的缓冲区数量有关。有些寄存器中间必须用SYNCDELAY 来延时。这类寄存器FX2 TechRefManual.pdf 上有说明。
对于EP0 ,用于系统握手,相关的寄存器操作基本上都由68013A 的内核(SIE )来完成了。
对于EP1, 分为OUT/IN 两组配置和寄存器。
对于EP2 ~EP8, 不分OUT/IN 输入输出,主要有EP2CFG/ EP2FIFOCFG/ EP2BCH/EP2BCL 寄存器。
7.3 什么是自动指针
自动指针是CYPRESS 提供的一个非常有用的特性。在数据交互的过程中,很多时候都涉及到数据的搬迁,比如从EP2OUT 收到的数据需要转发到EP6IN 上(一些转换类设备);再比如从RAM 中拷贝数据到EP4IN 上,传统的做法是申明两个指针,指向源和目的地址,然后用循环一个个字节拷贝,同时还要考虑增加指针地址,对于连续的空间这到不是问题,关键是如果数据需要拷贝到多个缓冲时,指针地址是循环的。这时候如果手工完成操作很容易出错。
因此CYPRESS 提供了两组自动指针,用的时候一组指向源,一组指向目的地址。然后循环拷贝数据就行了,自动指针会自动指向下一个源或目的空间,不论是否是循环地址方式。这样减少了程序出错的几率。
下面的程序将EP2OUT 接受到的数据拷贝到EP6IN 发送出去:
if(!(EP2468STAT & bmEP6FULL))
{ // check EP6 FULL(busy) bit in EP2468STAT (SFR), core set's this bit when FIFO is full
APTR1H = MSB( &EP2FIFOBUF );
APTR1L = LSB( &EP2FIFOBUF );
AUTOPTRH2 = MSB( &EP6FIFOBUF );
AUTOPTRL2 = LSB( &EP6FIFOBUF );
count = (EP2BCH << 8) + EP2BCL;
// loop EP2OUT buffer data to EP6IN
for( i = 0x0000; i < count; i++ )
{
// setup to transfer EP2OUT buffer to EP6IN buffer using AUTOPOINTER(s)
EXTAUTODAT2 = EXTAUTODAT1;
}
EP6BCH = EP2BCH;
SYNCDELAY;
EP6BCL = EP2BCL; // arm EP6IN
SYNCDELAY;
EP2BCL = 0x80; // re(arm) EP2OUT
}
}
APTR1H/APTR1H 通过MSB 和LSB 获取EP2FIFOBUF 的高位地址和地位地址。
EXTAUTODAT1 表示APTR1H/APTR1H 指向的数据。
AUTOPTRH2/AUTOPTRL2 通过MSB 和LSB 获取EP6FIFOBUF 的高位地址和地位地址。
EXTAUTODAT2 表示AUTOPTRH2/AUTOPTRL2 指向的数据。
7.4 CYUSB 和CYAPI 的关系
以前68013 上位机程序的编写过程中,应用程序端通过调用DeviceIoControl() API 或CREATEPIPE() API 与驱动进行交互,继而读写控制硬件设备,在新的68013A 的驱动中采用了两种新的调用方法:
第一种是继续使用DeviceIoControl() 函数读写,不同的是,IOCTL 控制字和老驱动完全不同,具体定义参考CYUSB.PDF 。用户可以通过这些底层API 完成操作。
第二种是使用CYPRESS 提供的面对对象的类,一共有9 个类,调用这些类的方法就可以和硬件打交道。这些类是对第一种方法的封装,使用起来非常简便。
用户可以根据需要选择这两种方法或混合使用,使用时需要加上头文件CyAPI.h 和cyioctl.h ,另外在项目中还要引用CyAPI.lib 。
7.5 同步和异步读写的比较
CYAPI 提供了同步和异步读写方式。同步方式的时候调用线程阻塞在哪里,直到读写到数据或超时;异步方式的时候调用线程立即返回。具体实例参考CYAPI.PDF 。
7.6 如何用C++ BUILDER 写上位机程序
1) 首先确定使用7.4 中的第几种方法,添加相应的头文件和库文件。
2) 连接USB 设备,确保驱动已经被正确加载。
3) 编写收发数据线程。通过开发板上的LED 或CYPRESS CONSOLE 或BUS HOUND 分析收发正确与否。
7.7 U 盘如何正确加载驱动
在WINDOWS 2000/XP 上U 盘使用的PID/VID 应该直接能加载操作系统默认的海量存储器的驱动程序。为了使用正确的PID/VID ,可以通过以下途径:
1) 找一个现有品牌的U 盘,看看他的PID/VID 是何值。
2) 在注册表中查找海量存储器信息。
8. 其他问题
1) 编写上位机的时候要注意添加异常处理。
2) 调试上位机的时候,USB 外设应正确连接。
3) 8051 其他模块的编写请参考相应书籍。