分享

CY68013 FPGA通信联调总结

 笔录收藏 2018-03-29

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的专业术语的含义及协议

详细摘抄

《EZ_USB FX2单片机原理、编程及应用 读书笔记》
《FX2 TRM 摘抄》

其余相关的Cypress USB开发资料:
Cypress的开发环境:
cy3684_ez_usb_fx2lp_development_kit_15.exe
CySuiteUSB_3_4_4_B184.exe

一个是开发固件程序的,里面自带了一个简化版的Keil;另一个是开发上位机软件的,还包含了Cypress默认的驱动程序、API库等等。安装的时候最好默认都安装在C盘下,会省很多麻烦。

cy7c68013 实现slave fifo: AN61345 + 例程demo

AN63787 - EZ-USB® FX2LP GPIF and Slave FIFO Configuration Examples Using an 8-Bit Asynchronous Interface

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./detail/34481.html
(2)02:CY7C68013特性介绍 http://blog./detail/34482.html
(3)03: CY7C68013A相关驱动版本说明 http://blog./detail/34483.html
(4)04: CY7C68013 Slave FIFO及PCB设计 http://blog./detail/34484.html
(5)05: CY3684 68013开发套件安装指南 http://blog./detail/34485.html
(6)06: USB 68013驱动程序的安装 http://blog./detail/34486.html
(7)07: USB68013 Driver数字证书一说 http://blog./detail/34487.html
(8)08: USB 68013 自定义VID&PID、版本、生厂商等信息 http://blog./detail/34488.html
(9)09: USB 68013调试工具的使用之CyConsole助手的使用 http://blog./detail/34489.html
(10)10: USB 68013调试工具的使用之Streamer USB传输测速 http://blog./detail/34490.html
(11)11: USB 68013调试开发之各种EEPROM下载处理办法以及为什么??http://blog./detail/34534.html
(12)12:USB68013 Firmware开发指南之 CY3684固件例程分析 http://blog./detail/34534.html
(13)13:USB68013 Firmware开发指南之Keil UV4工程配置选项 http://blog./detail/34533.html
(14)14:USB68013 Firmware开发指南之8051 SFR寄存器说明 http://blog./detail/34534.html

前方高能
CY68013资料网盘分享

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      = "."
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

2.1.2.2 程序下载

Cypress 提供了开发工具包里的 CyConsoleCyUSB Center,可以用来下载程序
程序下载分两种,

2.1.2.2.1 直接下载到RAM中运行

如果连接了eeprom,上电会从eeprom里面启动,已经配置了寄存器;
启动后再下载程序到RAM中运行,寄存器又被配置了一遍,但是这样可能会受到第一次配置的影响,USB通信出现问题。
一般是用哪一位就配置哪一位,其余的寄存器的bit保留原值。

regVal |= bmBIT0;
  • 1
  • 2

这样其余像 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设备

无法识别的USB设备

设备管理器上显示 unknown device
设备管理器显示

VID / PID 都没有显示
设备管理器查看VID PID
usb根本没有通信上!!!!

解决办法
推测原因
最后一个版本的程序下载进去有问题,即eeprom里的程序有问题,
然后又每次是通过eeprom来启动,
加载程序运行,然后每次枚举都不成功,所以显示未知设备

最关键的是要擦除eeprom里的原程序,然后更新为新程序即可。

还好,在Crazy Bingo的博客上找到了解决方案:
http://blog./crazybingo/p/34531
CrazyBingo CY68013 eeprom设计
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.

CY68013 TRM eeprom配置说明

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个端点的描述符!!
.a51配置

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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

上下两段换一下先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回来

PC端从USB处收到很多的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就行  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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 开发环境配置

fx2上位机开发 vs2013配置1

fx2上位机开发 vs2013配置2

剩下的就是

#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);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
2.3.2.2 EndPointOf( )
    Example
    UCHAR eptAddr = 0x82;
    CCyUSBDevice *USBDevice = new CCyUSBDevice(NULL);
    CCyUSBEndPoint *EndPt = USBDevice->EndPointOf(eptAddr);
    if (EndPt) EndPt->Reset( );
  • 1
  • 2
  • 3
  • 4
  • 5
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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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
  • 1
  • 2
  • 3

然后outbuf发送,在fpga端收到的就是0x0403,正好和发送的时候的数据是一样的!!!

fpga发送 0x0304, pc上先收到0x04,后收到0x03

    u8 inbuf[2];
    regVal = *(u16*)&(inbuf[0]);    //inbuf[0]= 0x04, inbuf[1]= 0x03; regVal = 0x0304
  • 1
  • 2

3. 核心代码

===It’s a secret!!!===

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多