Micro Framework USB Driver开发

简介:

为Micro Framework开发USB驱动也有一段时间了,随着开发的深入,对USB理解也渐渐清晰起来。

从系统架构上来说为Micro Framework开发USB驱动有三个层面的工作。一是针对USB芯片的驱动移植(很多ARM CPU都集成了USB功能),实现MF的HAL层要求的USB接口;二是开发PC平台上针对MF设备的USB驱动;三是编写应用程序(非Micro Framework应用程序),通过USB接口直接和MF设备通信(这个工作是我加的,其实完成前两步工作,就已经使MFDeploy和VS2008和设备正常通信了)。

下面我针对这三个层面,详细说一下我的开发工作。

一、USB驱动移植

这一步是最难的,特别是对USB没有任何了解的人来说。Micro Farmework的USB开发接口如下(含HAL层和PAL层的接口,其中PAL层的代码已经提供,不需要任何编程)。

1、CPU_USB_GetInterruptState Function

Determines whether there are currently interrupts pending for the USB port.

2、CPU_USB_Initialize Function

Initializes the client module at the driver layer.

3、CPU_USB_ProtectPins Function

Puts USB pins into a known state to prevent spurious inputs.

4、CPU_USB_RxEnable Function

Enables a specified USB port to receive data.

5、CPU_USB_StartOutput Function

Begins sending output to a specified USB port.

6、CPU_USB_Uninitialize Function

Uninitializes (shuts down) USB communications at the driver layer.

7、USB_ClearEvent Function

Clears one or more USB events.

8、USB_Flush Function

Flushes the buffers associated with USB ports.

9、USB_GetEvent Function

Gets the state of a USB event.

10、USB_Initialize Function

Initializes the USB subsystem.

11、USB_Read Function

Reads a block of data from a USB port.

12、USB_SetEvent Function

Sets the state of a USB event.

13、USB_Uninitialize Function

Initializes the USB subsystem.

14、USB_Write Function

Writes a block of data to a USB port.

其实接口什么样都无所谓,关键是首先你要让USB设备能work,让PC机能识别你的设备,USB开发的里程碑有三个,一是让PC机发现未知设备,二是让PC机识别USB设备,三是正确安装USB驱动(当然要能正常工作)。

1、第一步让USB识别你的设备,这一步可以说是最难,也可以说是最容易的一步,说它最难是因为这一步和硬件的正常工作非常相关,如果硬件工作不正常或USB接口有物理故障,这一步都很难通过,所以在开发USB驱动之前,一定确保硬件设备的USB能正常工作(比如在linux或Wince环境下能正常工作)。说它容易是因为仅需要正确配置一两个寄存器,不需要什么编程就能实现这一步。这个过程不需要了解太多的USB相关知识,只需要精读该芯片的英文技术文档即可。

 

2、第二步让PC机识别你的USB设备,这一步是最关键的一步,也是需要大量USB知识的一步。这一步仅需要实现USB的端点0(称控制端点或默认端点)相关的功能即可。

 

如果没有USB基础的人,这一步必须要充电,必须要知道USB相关协议规范,否则你就会寸步难行。我这里推荐一下两个人的blog,一个是大名鼎鼎的USB研究专家圈圈,写的关于USB的文章都非常透彻,相关链接(http://group.ednchina.com/93/240.aspx );另一个是蔡军生的关于USB的文章,写的也非常好,对开发很有帮助(http://blog.csdn.net/caimouse/archive/2007/03/24/1539835.aspx )。其次我推荐,如果大家有条件就要购买一本周立功编著的《USB 2.0与OTG规范及开发指南》,这可以说是一本USB2.0英文协议文档的翻译版,不过翻译的还不错(网上也流传了不少USB2.0中文协议文档,不过有些差强人意),可以相对比较准确地理解USB术语。对我来说,还是比较习惯读书的,在电脑上看大篇大篇的技术文档很容易看了后面忘了前面的。

这一步其实就是PC机对USB设备的盘查工作,有点类似公安局审犯人,如你是谁?什么背景?有什么能力等等。其中最关键的要问到USB设备的PID和VID,问到这一个才能安装相对应的驱动程序,当然获得相关的接口和端点配置也是非常重要的。详细的信息交互,这一步我就不多说了,协议上都说的非常清楚。这一步要说一点,就是设置地址这个环节最容易出错,PC机分配的地址收到后,一定要等返回相关ACK响应后,再修改设备的USB设备地址,否则很容易出问题。

这里推荐一下北航frank的文章《USB项目技术报告》,这个环节写的很清楚。

此外如果你手边有USB协议分析仪,那么你真是一个非常幸福的人,这一步就需要这个东东(我不太幸运,我是在调通USB驱动之后,才有的USB协议分析仪),Bus Hound工具虽然好用,但是在这一步却帮不上忙,它是要识别USB设备后才能正常监控USB数据流的,这对第三步的工作非常有帮助。

 

 

 

 

(USB通信过程一目了然,你会发现USB协议分析仪原来这么强大)。

 

 

 

注:Micro Framework的PAL层已实现相关通信交互的指令,你仅需要把USB通道打通即可,此外不要拘泥于MF porting kit中的USB驱动示例,要根据需要大胆一些调整相关逻辑。具体的要求请参见我以前的文章《MF Porting之USB驱动开发》http://yfsoft.blog.51cto.com/1635641/321265

 

第三步,安装驱动,如果第二步正确完成,PC机就会要求你安装USB驱动了。

 

     


二、PC USB驱动开发

Micro Framework的Porting kit开发包中已经提供了MF 设备的USB驱动源码(MFUSB_PortingKitSample),你仅需要修改一下Inf文件(主要修改相关的PID和VID,记住PID和VID仅是设备和相关驱动关联用的,除此之外没有其它任何用处),此外需要安装Windows DDK开发包,用来编译该驱动程序。相关说明如下:

To compile the USB drivers you must

1) install the DDK

2) open a command window for building (build environment must be initialized for that cmd window by calling setenv.cmd on the appropriate client directory)

3) build with the script build_usb_drivers in %SPOCLIENT%\Tools\scripts directory

   usage: build_usb_drivers.cmd DDK_INSTALLDIR

   example: build_usb_drivers.cmd c:\WINDDK\6001.18001

Output directories are under the drivers' source tree. Please move the sys files in the corresponding sub-directories in the inf folder before installing.

NOTE: the build_usb_drivers script will only build the MFUSB_PortingKitSample driver.  The MFUSB_DualInterface_PortingKitSample driver is the same

as the previous one but can handle 4 endpoints instead of two and allows debugging over USB the first pair of endpoints while reading/writing

on the other pair.

    由于MF设备仅支持3个端点(0,1,2),所以要扩展功能或增加端点,就需要你修改此程序的相关源码了(当然MF设备的USB驱动你也要相应地修改)。

 

三、USB应用程序开发

很多网上的此类程序大部分都是基于VC的,几乎找不到C#相关的源代码,即使有也发现文不对题,根本实现不了和设备的直接通信,网上有一个ICSharpCode.USBlib的库可以在C#中引用,据说功能还很强大,不过我在Vista和XP上好像没有测试成功,枚举USB设备时老出现异常。

幸好MFDeploy程序(MF SDK中的部署工具)是用C#开发的,所以深入研究该程序后,终于从中提取出一个USB读写类(MFDeploy程序太复杂了,我研究了好长时间才粗略理清相关逻辑脉络),终于很方便的用C#操作USB设备了。

 

 

 

 

相关接口:

   


 
 
  1. public interface IControllerLocal : IController  
  2.  
  3.     {  
  4.  
  5.         Stream OpenPort();  
  6.  
  7.     }  
  8.  
  9.     public interface IController  
  10.  
  11.     {  
  12.  
  13.         void ClosePort();  
  14.  
  15.         bool SendData(byte[] buf);  
  16.  
  17.         int Available { get; }  
  18.  
  19.         int ReadData(byte[] buf, int offset, int count);  
  20.  
  21.         void Start();  
  22.  
  23.         void Stop();  
  24.  
  25.         bool IsPortConnected { get; }  
  26.  
  27.         DateTime LastActivity { get; }  
  28.  
  29.     }  
  30.  
  31.     public interface IControllerHostLocal  
  32.  
  33.     {  
  34.  
  35.         Stream OpenConnection();  
  36.  
  37. }  
  38.  

应用代码:

 


 
 
  1. using System;  
  2.  
  3. using System.Drawing;  
  4.  
  5. using System.Windows.Forms;  
  6.  
  7. using System.Collections;  
  8.  
  9. using System.Threading;  
  10.  
  11. using Microsoft.SPOT.Debugger;  
  12.  
  13.    
  14.  
  15. namespace USBTest  
  16.  
  17. {  
  18.  
  19.     public partial class frmMain : Form  
  20.  
  21.     {  
  22.  
  23.         UsbEngine usb =null;  
  24.  
  25.         ArrayList pds=null;  
  26.  
  27.         private Thread m_ReadThread;  
  28.  
  29.    
  30.  
  31.         public frmMain()  
  32.  
  33.         {  
  34.  
  35.             InitializeComponent();  
  36.  
  37.             btnSend.Enabled = false;  
  38.  
  39.             btnUpdata_Click(null, null);  
  40.  
  41.         }  
  42.  
  43.    
  44.  
  45.         private void btnUpdata_Click(object sender, EventArgs e)  
  46.  
  47.         {  
  48.  
  49.             pds = UsbEngine.Enumerate();  
  50.  
  51.             cmbUSBList.Items.Clear();  
  52.  
  53.             foreach (PortDefinition pd in pds)  
  54.  
  55.             {  
  56.  
  57.                 cmbUSBList.Items.Add(pd.DisplayName);  
  58.  
  59.             }  
  60.  
  61.             if (cmbUSBList.Items.Count > 0 )cmbUSBList.SelectedIndex = 0;  
  62.  
  63.             else btnSend.Enabled = false;  
  64.  
  65.         }  
  66.  
  67.    
  68.  
  69.         private void cmbUSBList_SelectedIndexChanged(object sender, EventArgs e)  
  70.  
  71.         {  
  72.  
  73.             if (usb != null)  
  74.  
  75.             {  
  76.  
  77.                 btnSend.Enabled = false;  
  78.  
  79.                 usb.Dispose();  
  80.  
  81.             }  
  82.  
  83.             btnSend.Enabled = true;  
  84.  
  85.             usb = new UsbEngine((PortDefinition)pds[cmbUSBList.SelectedIndex]);  
  86.  
  87.             usb.Start();  
  88.  
  89.             m_ReadThread = new Thread(new ThreadStart(this.ReadDataThread));  
  90.  
  91.             m_ReadThread.IsBackground = true;  
  92.  
  93.             m_ReadThread.Start();  
  94.  
  95.         }  
  96.  
  97.    
  98.  
  99.         private void ReadDataThread()  
  100.  
  101.         {  
  102.  
  103.             byte[] bytData = new byte[1024];   
  104.  
  105.             while (btnSend.Enabled)  
  106.  
  107.             {  
  108.  
  109.                 try 
  110.  
  111.                 {                     
  112.  
  113.                     if (usb.Available> 0)  
  114.  
  115.                     {  
  116.  
  117.                         int intRet = usb.ReadData(bytData, 0, usb.Available);  
  118.  
  119.                         MethodInvoker method = delegate  
  120.  
  121.                         {  
  122.  
  123.                             string strData = "";  
  124.  
  125.                             for (int i = 0; i < intRet; i++)  
  126.  
  127.                             {  
  128.  
  129.                                 strData += bytData[i].ToString("X2") + " ";  
  130.  
  131.                             }  
  132.  
  133.                             txtRead.Text += strData;  
  134.  
  135.                         };  
  136.  
  137.                         this.txtRead.Invoke(method);  
  138.  
  139.                     }  
  140.  
  141.                     Thread.Sleep(100);   
  142.  
  143.                 }  
  144.  
  145.                 catch { }  
  146.  
  147.             }  
  148.  
  149.         }  
  150.  
  151.    
  152.  
  153.         private void btnSend_Click(object sender, EventArgs e)  
  154.  
  155.         {  
  156.  
  157.             if (usb == null || txtSend.Text.Length == 0 ) return;  
  158.  
  159.             try 
  160.  
  161.             {  
  162.  
  163.                 string[] strData = txtSend.Text.Split(new char[] { ' ' });  
  164.  
  165.                 byte[] bytData = new byte[strData.Length];  
  166.  
  167.    
  168.  
  169.                 for (int i = 0; i < bytData.Length; i++)  
  170.  
  171.                 {  
  172.  
  173.                     bytData[i] = (byte)Convert.ToInt32(strData[i], 16);  
  174.  
  175.                 }  
  176.  
  177.    
  178.  
  179.                 usb.SendData(bytData);  
  180.  
  181.             }  
  182.  
  183.             catch(Exception ex)  
  184.  
  185.             {  
  186.  
  187.                 txtRead.Text = "Send Error:" + ex.Message.ToString();  
  188.  
  189.             }  
  190.  
  191.         }  
  192.  
  193.         private void frmMain_FormClosing(object sender, FormClosingEventArgs e)  
  194.  
  195.         {  
  196.  
  197.             if (usb == null) return;  
  198.  
  199.             btnSend.Enabled = false;  
  200.  
  201.             usb.Stop();  
  202.  
  203.         }        
  204.  
  205.     }  
  206.  
  207. }  
  208.  

现在很多USB设备都是免驱的了,就是实现了HID封装,借助该通道和USB设备通信。我对该技术非常感兴趣,有时间可以深入研究一下。有此类经验的朋友也希望能分享一下。

 

还有一个值得高兴的事,Micro Framework美国微软研发团队终于向我们开放了TinyCLR源码,这是一个非常值得纪念的开始,意味着我们中国的MF团队又向美国的MF开发团队走近了一步,期待我们能在MF上走的更远。正如Lorenzo所说:We are very excited about this opportunity and we are confident that it will have a huge impact on our business.  This could be the beginning of a great collaboration. 

 

 






本文转自yefanqiu51CTO博客,原文链接:http://blog.51cto.com/yfsoft/321262,如需转载请自行联系原作者

相关文章
【.Net Micro Framework PortingKit – 13】LCD驱动开发
LCD的驱动开发还是比较繁琐一些的,因为LCD的驱动代码分散在三个目录中(题外话,我觉得针对.Net Micro Framework来说,最难的驱动是网卡驱动(特别是wifi驱动)、其次是USB驱动,和它们相比,LCD驱动就是小菜了)
764 0
【.Net Micro Framework PortingKit – 09】串口驱动
虽然在PC机中,串口渐行渐远,但是在嵌入式领域,串口仍可以说是如日中天,因为它造价低廉、并且编程也比较方便,在没有显示屏或输入设备的系统上,串口更是不可或缺,和超级终端一道,共同解决了信息显示和输入问题。
559 0
【.Net Micro Framework PortingKit(补) – 1】USB驱动开发
USB接口支持8个端点,数据传输支持三种模式:DMA、双缓冲、单缓冲,简单期间,我仅实现了单缓冲模式。首先,我们需要声明USB寄存器相对应的结构体,以期方便操作相关的寄存器。
634 0
【.Net Micro Framework PortingKit - 08】GPIO驱动
要点亮LED灯或获得输入IO的状态应该是比较容易的,打开端口时钟,然后读写相关的GPIO寄存器就可以了,但是要实现一个输入中断,就要费些周折了
496 0
【.Net Micro Framework PortingKit – 12】SysTick驱动开发
SysTick驱动有三个功用,一是我们上面所说的多任务和多线程支持;二是获得系统当前Tick,以此实现延时等待
639 0
|
前端开发
【.Net Micro Framework PortingKit - 06】设置芯片时钟
上两篇《修改启动代码&重写向量表》《SRAM初始化&设置NVIC中断表偏移》文章中,我们设置了中断向量表,初始化了RAM,并重设了向量表的地址,本篇文章是相对重要的一篇,我们将设置芯片时钟
578 0
|
Windows
在Corex-M3开发板上移植.Net Micro Framework系列文章
.NET Micro Framework 将 .NET 的可靠性和效率与 Visual Studio&reg; 的高生产率结合起来,以针对价格较低、资源受限的小型设备开发应用程序,可帮助人们使用熟悉的 Visual Studio 工具来构建托管的嵌入式应用程序。
652 0
|
存储 内存技术
.Net Micro Framework - USB Mass Storage功能实现
由于.Net Micro Framework的USB驱动架构中,没有为Mass Storage功能提供原生支持,所以除了要编写Mass Storage主体代码外,还需要在原有的USB驱动中添加部分枚举代码
903 0
.Net Micro Framework研究—带I2C总线的模拟器
I2C以前没有怎么接触过,所以做它的模拟功能,只能靠着感觉走,有不妥之处,还望方家指正。做出了spi相关的模拟功能,做I2C相对也就不难了,只不过用户操作I2C总线读写数据的时候要稍微麻烦一点。
658 0
【.Net Micro Framework PortingKit - 07】NVIC中断处理
Cortex-M3的中断架构和以往的ARM7、ARM9、ARM11有了很大的区别,IRQ、FIQ的概念的已经消失,随之而来的是NVIC中断管理(支持最多256个中断优先级,128级抢断)及中断向量表
639 0