Cyapi使用心得(1)--USB连接

用Cyapi也有一阵了,这个确实比EZusb的api好用,简单说下Cyapi的使用心得,在编程中应该注意的一些问题,毕竟,说起来,那个CYapi的说明文档讲的实在太简单了点,好多东西都讲得不明白,只能在使用中自己慢慢积累了。

首先说下前提,固件架构是EZ-USB FX2/FX2LP(CY7C68013),编译环境VC++ 6.0,驱动是Cyusb.sys。

上位机简单说下,建立一个MFC 单文档/对话框 应用程序;在路径项目中包含头文件cyapi.h和cyapi.lib所在的路径,最好移到最上面。然后手动导入cyapi.lib,注意是CV6_7的lib,不要导入BCB的。

下面讲得是按照USB一般工作流程来讲得。

(1)USB连接

1.首先要建立一个USB设备对象,文档里有说的了,copy一下

CCyUSBDevice *USBDevice = new   CCyUSBDev(Handle);

括号中的Handle是USB所关联对象的句柄,一般在MFC中直接就是m_hwnd。

2.然后就该是打开USB设备了,可以用到两个函数open();isopen()

这两个都可以用来打开USB设备,isopen()还可以判断能否获得USB设备句柄

一般来说,如果只有一个USB设备连接,可以这样打开:

USBDevice->open(0)    //打开0号USB设备

如果要判断,可以:

if(! USBDevice->open(0)) //打开失败

{messagebox("USB未连接");}

或者        if(!USBDevice->Isopen())

..........

如果连接有多个USB设备,那么可以枚举所有的USB,用到DeviceCount()函数;具体的可以参考cybulk的例子,执行USBDevice->DeviceCount()后,返回所连接的USB设备个数:

if (USBDevice->DeviceCount())   //保证至少有一个USB设备连接

{

for (i = 0; i < USBDevice->DeviceCount(); i++)    //枚举所有USB设备

{

USBDevice->Open(i);                   //打开第i号USB设备

m_DeviceListComBox.AddString(USBDevice->DeviceName);//所选择的当前设备名

}

}

Cyapi使用心得(2)--端点使用及其他USB属性获取

◆  在cybulk的例子中介绍了如何枚举固件中使用的所有端点,也就是使用多个端点的情况:

CCyUSBDevice *USBDevice =new CCyUSBDevice(m_hWnd); //USB设备

USBDevice->Open(0);    //打开0号USB设备

【1】首先获取所用的端点数目

int epts = USBDevice->EndPointCount();

EndPointCount();函数返回当前所用的端点数+1,也就是包含了控制端点。例如在固件接口描述符Interface Descriptor中设置Number of end points项(第5项)的值为4,则epts的值为4+1=5。

【2】定义端点指针

CCyUSBEndPoint *endpt;

CCyUSBEndPoint 建立一个端点对象,可建立所有的端点类型,控制端点,bulk端点,ISO端点等;

【3】开始枚举端点,并获得其属性:端点号,传输方向

for (i=1; i

{

endpt = USBDevice->EndPoints[i];    //EndPoints-端点列表,最大16.EndPoints[0]

//指向控制端点( CCyControlEndPoint)

//未使用的端点设置为NULL

if (endpt->Attributes == 2)    // Bulk Attributes--判断传输类型bulk,control,等

{

sprintf(s, "0xX", endpt->Address);

if (endpt->Address & 0x80)   //Address--判断传输方向in or out

//0x8_-in;0x0_-out

{

m_InEndptComBox.AddString(s); //最高位为8,in端点,添加到in组合框

m_InEndptComBox.SetItemData(m_InEndptComBox.GetCount()-1,i);

}

else

{

m_OutEndptComBox.AddString(s); //否则,最高位为0,out端点,

//添加到out组合框

m_OutEndptComBox.SetItemData(m_OutEndptComBox.GetCount()-1,i);

}

}

}

◆ 这样,就完成了某个具体端点的选择。从上面的代码来看,非常烦琐,如果只需要使用一个端点的画,那上面的代码无疑就显得冗长不够简洁了。仅使用一个端点,可以使用EndPointOf()函数,该函数直接使用指定的端点,返回其指针;例如,要使用端点2,in传输,那么,可以这样:

CCyUSBDevice *USBDevice =new CCyUSBDevice(m_hWnd); //USB设备

USBDevice->Open(0); //打开0号设备,

CCyUSBEndPoint *endpt = USBDevice->EndPointOf(0X82); //使用端点2,in传输

可以看到,上面的只需要3行代码,比枚举简洁方便多了。

◆ 至于获取USB其他属性,这里列出经常使用的几个,具体的可参考cyapi的文档,在CCyUSBDevice和CCyUSBEndPoint这两个类里可查询到。

USBDevice->DeviceCount()     //返回连接到电脑的USB设备个数,

//从0,1,2.。开始命名

USBDevice->DeviceName()     //返回USB设备名称,也就是固件中

//StringDscr2: 字段字符串

USBDevice->VendorID           //返回USB设备VID

USBDevice->ProductID           //返回USB设备PID

Cyapi使用心得(3)--控制传输

可以说,写USB上位机,控制传输肯定第一个要做的例子和试验了;因为固件不用很多代码,VC也不用很多代码就测试你写的USB上位机的正确与否,这里简单介绍下cyapi写控制传输的一些方法。

基本上,要对固件进行自定义命令(vendor)传输,通常都是用控制传输进行的。使用控制传输in或者out方式都可以实现对固件的自定义命令。

【1】out控制传输发送vendor命令

我想采用out方式应该比较符合大家的思维,因为是从上位机发命令到下位机,怎么看都应该是out而不是in。

例如你在固件里设置了out的接收buf:

BOOL DR_VendorCmnd(void)

{

switch (SETUPDAT[1])

{

case 0xDD:

{ temp=EP0BUF[0];

EP0BCH=0;

EP0BCL=1;

EP0CS |=bmHSNAK;

break;

}

default:

return(TRUE);

}

return(FALSE);

}

VC中:

CCyControlEndPoint* CtlEndpoint;   //定义一个控制端点

CtlEndpoint->Target    = TGT_DEVICE;       //不必关注,固定

CtlEndpoint->ReqType   = REQ_VENDOR;  //请求类型:自定义请求(标准请求等)

CtlEndpoint->Direction = DIR_TO_DEVICE;    //传输方向:主机->usb设备(out)

CtlEndpoint->ReqCode   = 0XDD;      //自定义请求码

CtlEndpoint->Value     = 0;     //这里的设定值将传给setupdat的【2:3】位

CtlEndpoint->Index     = 0;    //这里的设定值将传给setupdat的【4:5】位

PUCHAR buf=new UCHAR[1];

ZeroMemory(buf,1);             //用0填充buf区,填充大小(1字节)

long buflen=1;        //传输的其他字节数:cy控制台console中length的值

CtlEndpoint->XferData(buf,buflen);

当然,没有规定说一定必须传给下位机至少一个字节的数据;你也可以不传;不过最好下位机同样设置接收字节为0,否则小心有莫名奇妙的错误(XX内存不能为只读等等)。

将temp=EP0BUF[0];去掉,上位机:

PUCHAR buf=new UCHAR;   //用0填充buf区,填充大小(1字节)

long buflen=0;

CtlEndpoint->XferData(buf,buflen);

也是可以的,友情提示:控制传输请尽量用同步的xferdata()而不是异步的begindataxfer()。

【2】in控制传输发送vendor命令

基本上,跟out区别不大。固件中:

BOOL DR_VendorCmnd(void)

{

switch (SETUPDAT[1])

{

case 0xDD:

{

*EP0BUF=0XDD;

EP0BCH=0;

EP0BCL=1;

EP0CS |=bmHSNAK;

break;

}

default:

return(TRUE);

}

return(FALSE);

}

VC中:

CCyControlEndPoint* CtlEndpoint;   //定义一个控制端点

CtlEndpoint->Target    = TGT_DEVICE;  //不必关注,固定

CtlEndpoint->ReqType   = REQ_VENDOR; //请求类型:自定义请求(标准请求等)

CtlEndpoint->Direction = DIR_FROM_DEVICE;    //传输方向:usb设备->主机(in)

CtlEndpoint->ReqCode   = 0XDD;      //自定义请求码

CtlEndpoint->Value     = 0;     //这里的设定值将传给setupdat的【2:3】位

CtlEndpoint->Index     = 0;    //这里的设定值将传给setupdat的【4:5】位

PUCHAR buf=new UCHAR[1];

ZeroMemory(buf,1);           //用0填充buf区,填充大小(1字节)

long buflen=1;          //传输的其他字节数:cy控制台console中length的值

CtlEndpoint->XferData(buf,buflen);

这里的话,推荐尽量设置接收缓冲,不要将buflen设置为0.同样,友情提示:控制传输请尽量用同步的xferdata()而不是异步的begindataxfer()。

【3】另外,还有两个简化版本的函数Write(out传输)和Read(in传输)也可以进行控制传输,作用同XferData()是一样的,因为已经明确表示了是in还是out,所以Direction 项的值就省略了。只是看起来代码更加简洁,输入效率更高而已。基本上,大多数时候,我都是使用Write和Read。

CCyControlEndPoint* CtlEndpoint;   //定义一个控制端点

CtlEndpoint->Target    = TGT_DEVICE;   //不必关注,固定

CtlEndpoint->ReqType   = REQ_VENDOR; //请求类型:自定义请求(标准请求等)

CtlEndpoint->ReqCode   = 0XDD;      //自定义请求码

CtlEndpoint->Value     = 0;     //这里的设定值将传给setupdat的【2:3】位

CtlEndpoint->Index     = 0;    //这里的设定值将传给setupdat的【4:5】位

PUCHAR buf=new UCHAR[1];

ZeroMemory(buf,1);        //用0填充buf区,填充大小(1字节)

long buflen=1;       //传输的其他字节数:cy控制台console中length的值

CtlEndpoint->Write(buf,buflen);

Read的话同理。

Cyapi使用心得(4)--bulk传输

今天有空写以下bulk传输。bulk的话,cy开发包里有个例子cybulk写的很好,不过说实话,那个太烦琐了,基本上我们自己只用到其中的一部分,另外,就是局限性很大,例如它只是512字节的倍数,对于任意数目的字节貌似是不支持的,数据会不同步。

为了提高传输速度与效率,一般要把数据采集放在另外一个线程,单独开启一个bulk线程。恩,前面的还是稍微提一下,在打开USB,设定端点后,紧接着开启线程,进行bulk采集:

if (USBDevice->IsOpen()) {   //如果USB设备已经打开

bLooping = true;      //线程循环标志为真

XferThread = AfxBeginThread(XferLoop, this); //启动线程

}

然后是线程中的处理,在这里上位机用异步接收,创建异步事件:

OVERLAPPED inOvLap;

CVC_SimpleCyapiDlg *dlg = (CVC_SimpleCyapiDlg *) params;   //使该线程可访问

//CBulkLoopDlg类的所 有公有成员

inOvLap.hEvent   = CreateEvent(NULL, false, false, "CYUSB_IN");

线程循环:

bool success;

dlg->InEndpt->TimeOut = 120;

for (;dlg->bLooping;) {       //线程循环,直到循环标志blooping为假

LONG inlen ;

inlen = 512;

UCHAR *inContext = dlg->InEndpt->BeginDataXfer(inData,inlen,&inOvLap);

dlg->InEndpt->WaitForXfer(&inOvLap,TimeOut);

success = dlg->InEndpt->FinishDataXfer(inData,inlen, &inOvLap,inContext);

if (!success) dlg->bLooping = false;

}

主要是三步,调用三个函数BeginDataXfer,WaitForXfer,FinishDataXfer。按照手册上说的,BeginDataXfer发起异步传输,并且立即返回。也就是说,发起此次的inlen后,并不会等inlen传输完,而是立即开始下一次inlen字节传输;WaitForXfer,异步传输最大等待时间;FinishDataXfer,到这里才开始真正的写内存,将读到的数写到缓冲区indata中。

最后,完了别忘记释放对象:

CloseHandle(inOvLap.hEvent);

delete [] inData;

另外,如果要传输非512字节整数倍的数据,而且不是一次传输完的话,最好在线程中用SetXferSize()重新设置传输大小,否则会导致数据不同步。

usb fx2 cy68013 Cyapi使用心得的更多相关文章

  1. USB Loader使用心得之游戏名称、简介、背景音乐

    我在<WAD独立安装版USB Loader的下载和安装>(链接:http://www.cnblogs.com/duxiuxing/p/4255124.html)开头提到:“任何版本的USB ...

  2. USB学习笔记连载(八):FX2替换到FX2LP需要注意事项

    对于使用FX2的用户,可以升级到FX2LP,上述的应用笔记<AN4078-C>中就讲解了在升级中的注意事项.   必要的修改:   1.晶振的匹配电容需要更改,FX2LP是12pF,不过笔 ...

  3. USB上位机通信:CyAPI

    至今的工作中,有USB接口通信的需求,记录一下. 建立一个USB设备对象 CCyUSBDevice *USBDevice = new CCyUSBDev(Handle): 打开USB设备 一个USB设 ...

  4. android4.0.3源码之USB wifi移植心得

    http://blog.csdn.net/eastmoon502136/article/details/7850157 http://forum.cubietech.com/forum.php?mod ...

  5. EZ-USB FX2(68013)固件研究

    原始资料来自网络 整理日: 2015年2月12日 1. Welcome 算是给所有正在学习USB,还徘徊着不得其门而入的朋友一个入门的契机吧,我也深知入门的痛苦,有些人入门就是抱着那什么USB协议,包 ...

  6. 感受机房管理化繁为简-新款KVM使用心得

    感受机房管理化繁为简-新款KVM使用心得 一. 背景 随着网络应用的不断增多,各地机房服务器数量也随之增加,利用多传统主机切换器的方式已经无法满足目前这种区域广.设备多人员紧缺的现状,而且即使是使用了 ...

  7. 25.usb固件深入

    dscr51里放的是USB描述符表,EZ-USB在重枚举阶段会读取或设置相应的描述符: db    DSCR_DEVICE_LEN          ;; Descriptor length db   ...

  8. Android USB Host 通信程序

    换到了一家新公司,于是就有了新的项目.这次的项目 要用Android SDK与USB HID设备进行通信.第一次接触Android SDK,以及USB,记录下源程序.开发过程以及一些心得. 首先,要感 ...

  9. usb.ids

    # # List of USB ID's # # Maintained by Vojtech Pavlik <vojtech@suse.cz> # If you have any new ...

随机推荐

  1. pat 1120 Friend Numbers(20 分)

    1120 Friend Numbers(20 分) Two integers are called "friend numbers" if they share the same ...

  2. hdu 1874 畅通工程续 (floyd)

    畅通工程续Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  3. 领扣(LeetCode)最长和谐子序列 个人题解

    和谐数组是指一个数组里元素的最大值和最小值之间的差别正好是1. 现在,给定一个整数数组,你需要在所有可能的子序列中找到最长的和谐子序列的长度. 示例 1: 输入: [1,3,2,2,5,2,3,7] ...

  4. Robot Framework自动化测试环境搭建

    robotFramework是一个通用的自动化测试框架来进行验收测试和验收测试驱动开发模式,它具有易于使用的表格的测试数据和关键字测试驱动方法,其测试功能可通过实现与python或java的测试库进行 ...

  5. 简单说说基于JWT的token认证方式

    一.什么是认证 好多人不知道什么是认证,认证,其实就是服务端确认用户身份.Http协议是无状态的,客户端发送一条请求,服务端返回一条响应,二者就算做成一单买卖,一拍两散.在很久以前,互联网所能提供的服 ...

  6. 小白学 Python 爬虫(4):前置准备(三)Docker基础入门

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  7. IDEA最常用快捷键汇总+快速写出Main函数

    IDEA可以说是当下Java程序员日常开发的神器,但是想要发挥这款神器的牛逼威力,必须得熟练使用它的各种快捷键才行.本篇总结下使用IDEA(也就是IntelliJ IDEA )进行日常开发中最常用的快 ...

  8. PostGIS 存储过程调试

    说明: 在使用Postgis做路径分析时需要用到数据库的存储过程,但是存储过程逻辑很复杂,很想看一下每步的执行结果. 百度了一下,发现postgresql有插件可以支持调试存储过程. 解决方案: 1. ...

  9. vue 原生添加滚动加载更多

    vue中添加滚动加载更多,因为是单页面所以需要在跳出页面时候销毁滚动,要不会出现错乱.我们在mounted建立滚动,destroyed销毁滚动. mounted () { window.addEven ...

  10. 附012.Kubeadm部署高可用Kubernetes

    一 kubeadm介绍 1.1 概述 参考<附003.Kubeadm部署Kubernetes>. 1.2 kubeadm功能 参考<附003.Kubeadm部署Kubernetes& ...