如何在一个月内完成一个USB设备

如果想学习USB的开发,做一个简单的HID设备是一个很好的选择,你不用去编写驱动程序,因为操作系统都自带了。唯一要做的就是做固件(firmware)。
一个多月前,我开始了USB开发的学习,之前对硬件这东西是知之甚少了。这一个多月里,做PS/2键盘用了一个星期,复习六级用了一个星期,所以专心用于USB开发的时间也只有一个月。
大家都讲一个USB设备的开发周期是一年,一定不是指一个HID键盘。不过USB设备开发的艰难是真的,在开过的过程中,几次遇到问题,几天,甚至十几天都解决不了,那是何等的郁闷。不过,正是这些问题的出现,促使我去看HID标准、FX2的使用说明......促进了对USB标准、USB开发的了解。虽然现在只是开发出一个简单的HID,但我可以说,我对USB协议、HID协议、FX2的使用是比较了解的了,下一步的开发会顺畅很多。
我在这里只想跟大家分享一下我开发经验,让大家的开发再顺利些,起码能开发出一个简单的设备。以后我会补上LINUX下USB驱动开发的相关文章。我博客里还有更多东西(http://blog.csdn.net/manio)。
先列举一下我有的资源:
  CY7C68013A开发板一块
       CYPRESS control pannel
              程序文件夹中有:
FX2的TRM(ENGLISH,使用说明)
    FX2的EXAMPLE(这些很有用,帮助你建立概念)
       HID标准(ENGLISH)
       《USB技术及应用设计》(清华大学出版社 肖踞雄等著)
       《USB接口设计》(西安电子科技大学出版社 张弘著)
       GOOGLE
在第一个阶段,我只看《USB技术及应用设计》,了解USB协议的细节。我个人觉得这本书是很好的,讲得很详细,帮助你建立起一个对于USB的概念,比如说USB的几种传输、什么是包、什么是帧、什么是描述符、USB工作的流程、USB与主机的传输方式,等等。这些东西,在使用FX2开发时可能不能直接用上,但在你遇到问题时,进行测试时,你可以用一些很基本的原理来判断问题出在哪里。因为是带着问题(HID键盘怎么实现)来看书的,所以这一阶段,我已经了解了关于HID键盘的一些基本的东西,比如说键盘使用的是中断传输。
第二个阶段,开始使用开发板,进行实践。不过,在这里我遇到了最大的一个困难,就是不知为何,把CYPRESS的EXAMPLE下载到板子上,只有一个程序能够正确地运行。为了找出问题,我到处发帖,无奈的是,做USB开发的人其实还不是太多,更何况大家使用的板子不同,谁都不知道对方用的板子的情况。我就是在这个时候读遍了手头的文档,照着上面一步一步地做,最终还是运行不了。两个星期之后,我才想起为什么不打电话去给出这个板子的公司问问呢?然后就打了,在他们给了我一个配置方法之后,所有CYPRESS的程序都能在板子上运行了。原来是代码地址配置得不对,下载之后不能运行。那天,高兴得了差点上睡不着觉~~
后来,我阅读了几个CYPRESS的EXAMPLE,了解了BULK传输,了解了用到的一些寄存器,了解CYPRESS给的框架。然后,我就开始把原来找到的一个为EZ-USB写的HID键盘的固件代码改成FX2用的。
本来想,同一个公司的芯片,不就是改改寄存器,再看看有些其他的不同,改过来就是了(其实最后发现还真的是这样)。但这过程中,因为粗心,或者说因为对FX2设备的使用的了解还不是很深,又遇到了一些问题。我把它们分点列在下面,算是FAQ吧。
1.设备无法识别
这可能是因为EEPROM里的内容乱了。如果EEPROM的第一个字节决定设备下一步进行什么动作。如果乱了,设备可能发送错误的信息给主机,那么主机自然也就识别不了设备了。CYPRESS给了一个叫ZAPBIG的程序,用于恢复EEPROM的内容,CONTROL PANNEL的程序文件夹没有。如果谁要,我做乐意发给他。EEPROM恢复后,最后把FX2/EXAMPLE/EEPROM_IMAGE里的那个.IIC文件使用EEPROM下载按钮下载到EEPROM中,这样开发板上电后会自动运行KEIL的DEBUG MONITOR。
2.无法进行IN传输。
这个问题就比较低级了。因为我在ARM IN端点的时间,只写了EPxBCL,而没写EPxBCH。如果只知道一个数的低8位,而不知道8位,如何能确定一个字到底是多少?所以,在ARM一个端点时,端点计数器的值一定要明确给出。
3.当主机已经识别一个设备为HID键盘时,无法进行IN传输。
开始我以为原因是描述符出了问题,所以我把HID的标准给看了两遍,又参照别人的描述符文件,实在是找不出哪有错了。我在开始的时候也想到的端点使用的问题。我是使用EP6来作为IN端点的,但在看到有CYPRESS给的HID设备开发例子中用EP2来做很IN传输端点时,我也没觉得我用EP6作为IN传输端点有什么错,更何况,我也试着用EP2作为IN传输端点过,也是用不了。后来,我在网上看到一个例子用EP1来作为IN传输端点,抱着试试的心态,我改用EP1作为IN端点,奇迹般的,屏幕上出现了abcabcabcabcabc(当时的按钮设置有问题。。:))。至于为什么用其他端点不行,我仍然没有答案。如果谁知道,告诉我!
      
       在我调整好按键后,开发板可以很好的实现一个小键盘的功能了。现在看了,当初碰到的问题很是不值一提,不过总要经历的......
       文中有很多细节没有提到,大家可以GOOGLE一下。或者看看FX2的TRM。
 
       最后,我收藏夹里的链接给大家做参考:
Embeded
单片机
汇编
C语言
USB
Specifiction
Fx2
 
 
 
 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 在写 USB 驱动代码之前,你需要了解以下几点: 1. USB 设备USB 主机之间的通信协议。 2. USB 设备的软件架构,包括设备驱动程序和设备应用程序之间的关系。 3. 如何在操作系统中安装和配置 USB 设备。 4. 如何使用操作系统提供的 USB 接口编写代码。 根据这些信息,你可以尝试编写一个 USB 驱动程序的基本框架,如下所示: ```c #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/usb.h> /* 设备信息 */ #define VENDOR_ID 0x1234 #define PRODUCT_ID 0x5678 /* 定义设备和驱动程序之间的结构体 */ struct usb_device_driver { struct usb_device *udev; struct usb_interface *interface; }; /* 分配结构体内存 */ struct usb_device_driver *driver; /* 定义 USB 设备结构体 */ static struct usb_device_id id_table [] = { { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, { }, }; MODULE_DEVICE_TABLE(usb, id_table); /* 驱动程序初始化函数 */ static int __init usb_driver_init(void) { int result; /* 分配内存 */ driver = kzalloc(sizeof(struct usb_device_driver), GFP_KERNEL); if (!driver) return -ENOMEM; /* 注册驱动程序 */ result = usb_register(&driver->udev); if (result) goto error; /* 获取设备接口 */ driver->interface = usb_find_interface(&driver->udev, 0); if (!driver->interface) { result = -ENODEV; goto error; ### 回答2: 要写一个 USB 驱动代码,需要先理解 USB 接口的工作原理和 USB 设备的通信协议。 首先,需要创建一个 USB 驱动程序的框架。这个框架可以是一个基于操作系统提供的 USB 驱动接口的程序。驱动程序可以通过这个接口与操作系统的 USB 子系统进行通信,并获取 USB 设备的插入和拔出事件。 接下来,需要初始化 USB 子系统并与 USB 设备建立连接。可以通过操作系统提供的 USB 接口函数来完成初始化和连接的过程。初始化包括分配端点、分配内存缓冲区等工作。连接过程包括搜索并识别设备,获取设备的描述符等操作。 一旦连接成功,就可以开始数据的传输。可以通过操作系统提供的接口函数来发送和接收数据。根据 USB 设备的特性,可以使用同步传输、中断传输或批量传输等方式进行数据传输。 在数据传输过程中,需要根据 USB 设备的协议规定进行数据的打包和解包,以确保数据的正确传输和解释。这需要根据设备的通信协议进行编程。 当 USB 设备的状态发生变化时,驱动程序需要及时响应并进行处理。比如设备的插入和拔出事件,驱动程序需要进行连接和断开的操作。 最后,需要进行错误处理和异常情况的处理。可以通过检测错误码和异常情况来进行相应的处理和恢复机制。 总的来说,编写一个 USB 驱动代码需要了解 USB 接口的工作原理和通信协议,利用操作系统提供的接口函数进行数据传输和设备管理,同时要考虑和处理各种错误和异常情况。 ### 回答3: USB(Universal Serial Bus)驱动程序是用于与USB设备进行通信和控制的软件模块,因此需要根据具体的USB设备类型和操作系统需求进行编写。 以下是一个简单的USB驱动代码示例: ```c #include <linux/module.h> #include <linux/usb.h> #include <linux/kernel.h> static int usb_device_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(interface); printk(KERN_INFO "USB驱动:设备已连接 (Vendor ID = 0x%04X, Product ID = 0x%04X)\n", udev->descriptor.idVendor, udev->descriptor.idProduct); // 进行设备初始化和通信控制 return 0; // 返回0表示驱动加载成功 } static void usb_device_disconnect(struct usb_interface *interface) { printk(KERN_INFO "USB驱动:设备已断开\n"); // 进行设备的断开处理和资源释放 } static struct usb_device_id usb_device_table[] = { { USB_DEVICE(0x1234, 0x5678) }, // 用于匹配特定的Vendor ID和Product ID {} // 结束标志 }; MODULE_DEVICE_TABLE(usb, usb_device_table); static struct usb_driver usb_device_driver = { .name = "usb_device_driver", .probe = usb_device_probe, .disconnect = usb_device_disconnect, .id_table = usb_device_table }; static int __init usb_driver_init(void) { int result = usb_register(&usb_device_driver); if (result < 0) { printk(KERN_ERR "USB驱动:加载失败,错误码%d\n", result); return result; } printk(KERN_INFO "USB驱动:加载成功\n"); return 0; } static void __exit usb_driver_exit(void) { usb_deregister(&usb_device_driver); printk(KERN_INFO "USB驱动:卸载成功\n"); } module_init(usb_driver_init); module_exit(usb_driver_exit); MODULE_LICENSE("GPL"); ``` 上述代码是一个简单的USB驱动程序示例,主要包括设备连接和断开的处理函数,以及驱动的初始化和退出函数。其中,通过定义`usb_device_id`结构体可以匹配特定的Vendor ID和Product ID,从而控制与特定的USB设备进行通信和控制。 需要注意的是,上述代码适用于Linux操作系统,使用的是Linux内核提供的USB驱动框架。不同的操作系统和开发环境可能存在一些差异,需要根据具体情况进行适配和修改。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值