1. 简介
CY68013是一款USB 2.0芯片,常用作fpga与pc的接口芯片,其硬件可以自动处理USB协议,也可以在里面下载对应的固件程序,由固件程序来完成USB协议的通信。我们只关心USB数据的传输,协议的不作深究,能用就行。
2. 开发
2.1 CY68013
2.1.1 CY68013资料摘抄
主要参考文档:
参考文档 | 描述 |
---|---|
EZ-USB_TRM_001-13670_0E.pdf | fx2的参考手册,相当于UserGuide |
CY7C68013A.pdf | fx2的电气特性,相当于DataSheet,slave fifo各个控制信号的时序图在这份文档中有写 |
EZ-USB FX2单片机原理、编程及应用_钱峰编.pdf | 实际上是TRM的翻译,翻得通俗一点 |
AN61345.pdf | Cypress 提供的 slave fifo的接口介绍,以及demo代码的分析 |
圈圈教你玩USB.pdf | 这个是一款飞利浦的USB PHY芯片的参考书,USB协议需要自己处理,有助于理解USB的专业术语的含义及协议 |
详细摘抄
《FX2 TRM 摘抄》
其余相关的Cypress USB开发资料:
Cypress的开发环境:
cy3684_ez_usb_fx2lp_development_kit_15.exe
一个是开发固件程序的,里面自带了一个简化版的Keil;另一个是开发上位机软件的,还包含了Cypress默认的驱动程序、API库等等。安装的时候最好默认都安装在C盘下,会省很多麻烦。
cy7c68013 实现slave fifo: AN61345 + 例程demo
AN58069 - Implementing an 8-Bit Parallel MPEG2-TS Interface Using Slave FIFO Mode in FX2LP
AN63620 - Configuring a Xilinx Spartan-3E FPGA Over USB Using EZ-USB FX2LP?
CrazyBingo系列:
Crazy Bingo CY68013开发例程
链接地址可能不准,直接百度即可,AET与非网上都有
(1)01:USB+FPGA摄像头算法处理-持续更新中 http://blog.chinaaet.com/detail/34481.html
(2)02:CY7C68013特性介绍 http://blog.chinaaet.com/detail/34482.html
(3)03: CY7C68013A相关驱动版本说明 http://blog.chinaaet.com/detail/34483.html
(4)04: CY7C68013 Slave FIFO及PCB设计 http://blog.chinaaet.com/detail/34484.html
(5)05: CY3684 68013开发套件安装指南 http://blog.chinaaet.com/detail/34485.html
(6)06: USB 68013驱动程序的安装 http://blog.chinaaet.com/detail/34486.html
(7)07: USB68013 Driver数字证书一说 http://blog.chinaaet.com/detail/34487.html
(8)08: USB 68013 自定义VID&PID、版本、生厂商等信息 http://blog.chinaaet.com/detail/34488.html
(9)09: USB 68013调试工具的使用之CyConsole助手的使用 http://blog.chinaaet.com/detail/34489.html
(10)10: USB 68013调试工具的使用之Streamer USB传输测速 http://blog.chinaaet.com/detail/34490.html
(11)11: USB 68013调试开发之各种EEPROM下载处理办法以及为什么??http://blog.chinaaet.com/detail/34534.html
(12)12:USB68013 Firmware开发指南之 CY3684固件例程分析 http://blog.chinaaet.com/detail/34534.html
(13)13:USB68013 Firmware开发指南之Keil UV4工程配置选项 http://blog.chinaaet.com/detail/34533.html
(14)14:USB68013 Firmware开发指南之8051 SFR寄存器说明 http://blog.chinaaet.com/detail/34534.html
2.1.2 Firmware开发
2.1.2.1 CY68013驱动安装
Cypress提供了官方驱动,win7 x64 32都是支持的
安装上驱动以后,可以使用库函数来和fx2芯片进行通讯。
需要修改 cyusb.inf 文件来安装对应的驱动
;for all platforms
;在这里增加对应的 VID 和 PID 设备
[Device]
%VID_XXXX&PID_XXXX.DeviceDesc%=CyUsb, USB\VID_XXXX&PID_XXXX
;for windows 2000 non intel platforms
[Device.NT]
%VID_XXXX&PID_XXXX.DeviceDesc%=CyUsb, USB\VID_XXXX&PID_XXXX
;for x86 platforms
[Device.NTx86]
%VID_XXXX&PID_XXXX.DeviceDesc%=CyUsb, USB\VID_XXXX&PID_XXXX
;for x64 platforms
[Device.NTamd64]
%VID_XXXX&PID_XXXX.DeviceDesc%=CyUsb, USB\VID_XXXX&PID_XXXX
[Strings]
;在这里添加对应于自己的VID PID的描述
CYUSB_Provider = "Cypress"
CYUSB_Company = "Cypress Semiconductor Corporation"
CYUSB_Description = "Cypress Generic USB Driver"
CYUSB_DisplayName = "Cypress USB Generic"
CYUSB_Install = "Cypress CYUSB Driver Installation Disk"
VID_XXXX&PID_XXXX.DeviceDesc="Cypress USB Generic Driver (3.4.7.000)"
CYUSB.GUID="{AE18AA60-7F6A-11d4-97DD-00010229B959}"
CYUSB_Unused = "."
2.1.2.2 程序下载
Cypress 提供了开发工具包里的 CyConsole 和 CyUSB Center,可以用来下载程序
程序下载分两种,
2.1.2.2.1 直接下载到RAM中运行
如果连接了eeprom,上电会从eeprom里面启动,已经配置了寄存器;
启动后再下载程序到RAM中运行,寄存器又被配置了一遍,但是这样可能会受到第一次配置的影响,USB通信出现问题。
一般是用哪一位就配置哪一位,其余的寄存器的bit保留原值。
regVal |= bmBIT0;
这样其余像 bit7->1 都是保留原值,可能会被第一次配置干扰。
爆出
error code 997,实际上是last error = 997
cy7c68013都搭配有eeprom,eeprom里面存的程序,上电启动的时候,先把程序从eeprom加载到内部ram中,即0000-0x3FFF的区域,然后才开始运行;注意与USB相关的寄存器配置以及EP buffer都在上面0xE200-0xFFFF区域!!!这个区域不会有程序,也就是说程序下载的时候不会覆盖到这片区域。初始程序启动后,对usb相关寄存器进行了配置,然后连上usb,驱动配合脚本自动下载固件,这个固件被下载到0x0000-0x3FFF区域去执行,不会覆盖0xE200-0xFFFF区域的USB急促安琪和EP buffers,下载期间不会断电。新下载的固件启动执行,对USB regs 和EP buffers进行操作,但是只是改变指定位的数据,其他设置保留eeprom中初始程序的USB寄存器设置,所以会发现,新固件的代码功能并没有提现出来或者说不正常!!! 直接把程序烧写到eeprom就可以了!!!
2.1.2.2.2 下载到附带配套的eeprom芯片里
上电从eeprom加载程序运行
下载程序到eeprom中造成USB通信异常的案例
① 现象描述:
一开始的时候,向CY68013的eepron里下载程序,能和pc通信上,只是数据有些不正常;
修改程序以后,重新下载程序到CY68013的eeprom中,再上电,pc提示无法识别的usb设备
设备管理器上显示 unknown device
VID / PID 都没有显示
usb根本没有通信上!!!!
② 解决办法
推测原因
最后一个版本的程序下载进去有问题,即eeprom里的程序有问题,
然后又每次是通过eeprom来启动,
加载程序运行,然后每次枚举都不成功,所以显示未知设备
最关键的是要擦除eeprom里的原程序,然后更新为新程序即可。
还好,在Crazy Bingo的博客上找到了解决方案:
http://blog.chinaaet.com/crazybingo/p/34531
EZ_USB手册上如是说:
The EZ-USB boot loader supports two I2C EEPROM types:
■ EEPROMs with slave address 1010 that use an 8-bit internal address (for example, 24LC00, 24LC01/B,24LC02/B).
■ EEPROMs with slave address 1010 that use a 16-bit internal address (for example, 24AA64, 24LC128, 24AA256).
EEPROMs with densities up to 256 bytes require only a single address byte; larger EEPROMs require two address bytes. The EZ-USB must determine which EEPROM type is connected — one or two address bytes — so that it can properly read the EEPROM.
The EZ-USB uses the EEPROM device-address pins A2, A1, and A0 to determine whether to send out one or two bytes of address. As shown in Table 13-11, single byte address EEPROMs must be strapped to address 000, while double byte address EEPROMs must be strapped to address 001.
EEPROM是可以配置地址的,A2,A1,A0就是用来配置地址的,而fx2只认 001 的地址,
只要改变了eeprom的地址,eeprom就会失效,fx2就无法从eeprom加载程序,只能硬件回复usb请求
1)先短路J13,使得A0变低
2)usb连接到pc,检测到usb设备,驱动无法自动安装
3)手动安装对应的cypress usb驱动
4)断开J13,使A0变高电平
5)打开CyConsole,下载程序到eeprom,ok,usb通信恢复
2.1.2.3 .a51文件的作用
注意,.a51的文件描述符是用来上报给pc机的,用库函数获取到的描述符都是从这个.a51里来的
相当于这个文件决定了跟pc报告说我有哪些端点,以及端点的大小
.a51文件必须和fx2真正在运行时配置的端点一致才可以,否则会造成,上位机调用库函数和fx2通讯不上
HighSpeedConfigDscr里面需要改成4个端点的,而且下面要写4个端点的描述符!!
2.1.2.4 Max PktSize含义
最大只能发这么多
端点大小 和 Max PktSize是不一样的
端点大小是缓存区的大小,2和6可以配置为512 和 1024两种
4 和 8就只能配置为512
Max PktSize可以设置为64,最大usb包长为64
2.1.2.5 芯片没办法软件复位!!!!
如果端点fifo满了,仍旧连续发送,芯片会挂点,软件复位没有用,必须重新上电,hard reset!!!
清空FIFO,在TD_Poll()中进行FIFO_RESET,严格来说是在outpkt_end后进行FIFO_RESET,然后再bulkout就失败了!!!!不知道什么原因!!!
//FIFO复位
SYNCDELAY;
FIFORESET = 0x80; // activate NAK-ALL to avoid race conditions
SYNCDELAY; // see TRM section 15.14
FIFORESET = 0x02; // reset, FIFO 2
SYNCDELAY; //
FIFORESET = 0x04; // reset, FIFO 4
SYNCDELAY; //
FIFORESET = 0x06; // reset, FIFO 6
SYNCDELAY; //
FIFORESET = 0x08; // reset, FIFO 8
SYNCDELAY; //
FIFORESET = 0x00; // deactivate NAK-ALL
SYNCDELAY; //
//清空usb残留,不让usb残留提交到slave fifo接口处
//这样fpga端在接收的时候不会收到乱七八糟的数据
//加了下面这几句话,再在这个后面执行FIFORESET就不能bulkout了,不知为何
OUTPKTEND = 0x82; // Arm both EP2 buffers to "prime the pump"
SYNCDELAY;
OUTPKTEND = 0x82;
SYNCDELAY;
OUTPKTEND = 0x84;
SYNCDELAY;
OUTPKTEND = 0x84;
SYNCDELAY;
上下两段换一下先OUTPKTEND 然后再 FIFORESET就会出现上面说的问题
2.2 fpga
2.2.1 slve fifo 接口控制通讯
参考文档:
AN61345.pdf
CY69013A.pdf
截图全部取自CY7C68013A的datasheet,不是TRM,TRM里面没有标出来时间
IFCLK是fx2输入脚的IFCLK,确实是上升沿去采样的,
2.2.1.1 基本连接
2.2.1.2 时序分析
这里只采用同步读写的方式!!!
读:
ToeOn 以后的数据才是有效的数据。
写:
最坏情况下,写入以后,满的FLAGS需要13.5ns才能出来,超过周期的一半了,得等到下降沿以后才能检测到IN FIFO满
2.2.1 实验调试经历
2.2.1.1 stream_in
2.2.1.1.1 上电后fpga发送了很多0x00回来
一开始以为是fifo里面有缓存,而且因为配置的是512 x4大小,所以收到了512 x4的 0x00 实际上是fpga实际一直控制在写00 00
用万用表来测量fx2的slwr脚一直显示为0V!!!
后来发现,fpga管脚锁错了!!!!!!没有把slwr脚锁到对应的fx2的slwr脚,造成了slave fifo的异常写入
心中千万只草泥马呼啸而过………………
2.2.1.1.2 fpga的短包发送出现问题
发送短包要拉低pkt_end信号脚,但什么时候拉低,某不知名网友说:
pkt_end <= slwr_n
然而,
pkt_end <= slwr_n 处理短包,结果不对,完全不对!!!
才发到001D,就写了0x1D个数,flagd就拉低了,显示fifo满了,但是fifo可是512bytes x4大小的!!!
尝试pkt_end <= ‘1’; 每次等齐512字节自动发送的话,这样子,flagd就是正常的。
估计是pkt_end的操作有问题
重新翻看时序图:
短包发送时序图
还有TRM里的一句说明
then pulse the PKTEND pin,就是slwr_n写到fifo里面,然后都结束了,再拉低PKTEND一个周期就可以了。
修改后重新下载,实验结果符合预期,能够正常收到短包数据,每次7个16bit数据;
Bulk in failed是故意尝试只让fpga发一次,pc机上请求读取两次中的第二次,返回失败是正常的,因为fifo里确实没有数据了。
另外注意一点,EP6FIFOCNT看起来一直为0,实际上含义不一样,只要pkt_end以后,EP6FIFOCNT就会被清0,说这些数据已经被打包出去了,但是实际还是占用空间的,FIFO的flag该是Full还是full,所以会出现EP6 为Full,但是EP6FIFOCNT= 0。
超过512bytes用pktend发送出现问题:
开启短包发送,但是fpga发送超过512字节给pc的时候出现问题,会收到两个512字节数据,后面的512字节是一串乱码
原因:
fx2程序中开了autoin,然后fpga发送端又有pkt_end拉低一个周期造成的矛盾,到了512字节已经autoin发送了,然后由pkt_end发送一遍,第二遍的时候发送的不知道是什么数据
2.2.1.2 stream_out
2.2.1.3 bulk_loopback
配置情况
fpga内配置1024 x16bit的fifo
fx2 配置为
EP2OUT 512 x4
EP6IN 512 x4
连续发9个512byte过去,然后收到的数据并不完整,收到第5包,后面的数据就没有了(工程关闭ep6 autoin,无论是长包还是短包,都是用pkt_end来驱动发送的)
ep6fifocnt 一直为2
通过chipscope观察,发现死在了read_sig状态
实际上是因为fpga内部fifo提前发出了full信号,即没到1024就发出了full信号,导致没法把存在EP2OUT端点的6,7,8,9包数据全部都写入fpga内部fifo,还剩了2个byte数据在EP2OUT内,EP2OUT数据又没读空,死在read状态过不去,状态又没法跳转。
修正后,只能读到7包数据,最后两个数还不对,变成了08
发现第7包的前两个字节会丢
在第七包只发了两个字节4C4B的情况下,什么也收不到
chipscope
dout能看到有4C4B说明确实这个值是写入到fpga的fifo中的,但是从fifo中读出然后写入到fx2的slave fifo中是有问题的。
关键的关键是,EP6IN fifo满的时候,按照检测flagd然后控制rden,又由fifo返回的valid信号来驱动slwr_n, 就会造成少写入一个数据到EPIN6 FIFO里面,但是这个数据已经从fpga内部fifo中读出来了,就造成了丢失一个数据。归根到底,是因为valid信号和rd_en信号有一个时钟周期的延时。
为了弥补这一个数据,需要在fx2中设置EP IN full的标志位提前一个单位告知FIFO FULL,
EP6FIFOCFG = 0x41; // AUTOIN=0, WORDWIDE=1 , ZEROLENIN=0, INFM1 = 1,这样就不会漏数据了。
数据通路分析:
EP2OUT 到 fpga内部fifo:
在往fpga内部fifo写的时候,fpga内部fifo会提前一个单元给出fifo满信号,这样会导致有一个单元的数据,这里对应2bytes数据,残留在EPOUT FIFO中,得等到pc把EPIN fifo的数据读掉一些,然后fpga内部fifo释放出来一些空间,才会把EPOUT的残留数据读出来写入fpga内部fifo。但是这个并不影响最终pc接收的情况,因为看起来还是和原来一样512bytes取出来。
fpga内部fifo 到EP6IN:
就是前面关键的关键分析的
2.2.2 fpga小技巧
2.2.2.1 同步电路外面加一层逻辑电路保护,保证不会误读出来然后没人接收
2.2.2.2 inout口处理
fdata_in专门用作输入,真实值 或者 0
data_out专门用作输出,真实值 或者 0
--fdata_in作为输入
process (sloe)
begin
if (sloe) --输入
fdata_in <= fdata;
else
fdata_in <= conv(0, 16);
end if;
end process;
data <= fdata_in --以后输入就从fdata_in去取就行
--data_out作为输出
process (sloe)
begin
if (sloe = ‘0‘) --输出
fdata <= data_out;
else
fdata <= (whenothers=>‘z‘);
end if;
end process;
data_out <= "xxxxxxxxxx"; --以后输出都给到data_out就行
2.2.2.3 高低字节序
从pc到fpga:
fpga fifo
din 16
dout 64
din 按顺序写入0xabcd, 0xefgh,0xijkl, 0xmnop
dout 0xabcd_efgh_ijkl_mnop (即先存入的为高16bit)
一个数 Num = 0x0102030405060708;
全部是以高字节在高地址来画的表格,字节数变大时间在后
路径 | byte0 | byte1 | byte2 | byte3 | byte4 | byte5 | byte6 | byte7 |
---|---|---|---|---|---|---|---|---|
inbuf | 0x08 | 0x07 | 0x06 | 0x05 | 0x04 | 0x03 | 0x02 | 0x01 |
slave fifo dout 16bit | 0x08 | 0x07 | 0x06 | 0x05 | 0x04 | 0x03 | 0x02 | 0x01 |
fpga fifo din 16bit | 0x08 | 0x07 | 0x06 | 0x05 | 0x04 | 0x03 | 0x02 | 0x01 |
fpga fifo dout 64bit | 0x02 | 0x01 | 0x04 | 0x03 | 0x06 | 0x05 | 0x08 | 0x07 |
读出来 Num2 = 0x0708050603040102
Num2 和 Num1 的关系为,高低字节倒序排列,然后每16bit内部两字节交换。
想要输入Num 和 读出来的 Num2相等,
必须先对 Num 作 高低字节倒序排列,然后每16bit内部两字节交换
从fpga 到 pc
fpga fifo
din 32
dout 16
din 0xab_cd_ef_gh
dout 按顺序读出 0xabcd, 0xefgh
同理的,reg fifo out dout为32位, Num = 0x05060708;
byte3为最高字节
路径 | byte0 | byte1 | byte2 | byte3 |
---|---|---|---|---|
reg fifo out din 32bit | 0x08 | 0x07 | 0x06 | 0x05 |
reg fifo out dout 16bit | 0x06 | 0x05 | 0x08 | 0x07 |
slave fifo dout | 0x06 | 0x05 | 0x08 | 0x07 |
outbuf | 0x06 | 0x05 | 0x08 | 0x07 |
Num2 = 0x07080506
2.2.2.4 用modelsim仿真的时候会出现红色线段
红色线段表示非稳定状态,数值状态为未知,可能的原因如下
① 信号未赋予初始值
② inout口处理不当,两端同时进行out输出造成不稳定状态
2.2.2.5 chipscope无法捕获信号
停留在转圈圈的状态,提示 waiting for core to be armed,slow or stopped clock
这个问题肯定是因为输给chipscope的时钟没有跑起来!!!
有一些复位信号的原因,外部复位信号没有锁定也没有赋值,可能就接到pll的rst上,导致一直在复位,时钟就没有跑起来
时钟最好从pll的bufg之后接到chipscope上!!!
奇奇葩葩的问题:
今天碰到一个很奇怪的现象,原来的工程死活就不行,fpga程序一烧进去,就收到一大坨数据,EP6直接满了,EP8也有数据,特别奇怪!!!后来换了一个工程就好了
2.3 上位机
2.3.1 开发环境配置
剩下的就是
#include "CyAPI.h"
就可以使用了
2.3.2 Cypress 库函数的使用
Cypress C++库函数参考文档
CyAPI.pdf
主要函数
2.3.2.1 open()
Example
CCyUSBDevice *USBDevice = new CCyUSBDevice(NULL);
// Attempt to open device #0
if (USBDevice->DeviceCount() && !USBDevice->Open(0)) {
USBDevice->Reset();
USBDevice->Open(0);
}
2.3.2.2 EndPointOf( )
Example
UCHAR eptAddr = 0x82;
CCyUSBDevice *USBDevice = new CCyUSBDevice(NULL);
CCyUSBEndPoint *EndPt = USBDevice->EndPointOf(eptAddr);
if (EndPt) EndPt->Reset( );
2.3.2.3 XferData( )
这个函数 IN 和 OUT端点都可以用的, bulkin的话就是接收,bulkout就是发送
Example
CCyUSBDevice *USBDevice = new CCyUSBDevice(NULL);
unsigned char buf[] = "hello world";
LONG length = 11;
if (USBDevice->BulkOutEndPt)
USBDevice->BulkOutEndPt->XferData(buf, length);
2.3.2 调试
1)控制端点操作不成功
一个是因为地址不对,另一个是因为长度不对,length必须是LONG,然后如果有连续的函数套用,必须把长度设成可更改的引用,LONG &lenth,否则会返回失败。
2)上位机短包发送限制
每一个短包实际上占用了一个buffer缓冲,512x4 16bit的端点配置,一共就只能发送4次短包就会满
如下图所示:
每次发送12字节,只能发送4次,再发送就失败了!!!!
而且一旦出现发送失败,无论是软件复位还是其他什么的都不好使!!!必须重新上电才可以!!!
3)大小端顺序
要注意,无论是发还是收,都是小端序。
PC机先发0x03,再发0x04, 在slave_fifo里读出来是0x0403
另外pc机内部于是小端序,所以
u8 outbuf[2];
*(u16*)&(outbuf[0]) = 0x0403; //outbuf[0]= 0x03, outbuf[1]= 0x04
然后outbuf发送,在fpga端收到的就是0x0403,正好和发送的时候的数据是一样的!!!
fpga发送 0x0304, pc上先收到0x04,后收到0x03
u8 inbuf[2];
regVal = *(u16*)&(inbuf[0]); //inbuf[0]= 0x04, inbuf[1]= 0x03; regVal = 0x0304
3. 核心代码
==It’s a secret!!!==