前进的每一步,都是学习,是成长。
USB固件开发总结(二)[转载]
  • 首页 > 嵌入式系统 > 系统与软件设计
  • 作者:最爱香茗
  • 2018年5月22日 22:47 星期二
  • 浏览:419
  • 字号:
  • 评论:0
  • 3.2 固件在USB设备设别阶段的编程思路

    一般地,USB设备接口芯片会产生一些中断来通知程序员特定事件的发生。譬如说,EP0(缺省控制端点) SETUP包的到达,EP0 IN或OUT事务的发生等等。控制传输是分三个阶段的:建立阶段,数据阶段,状态阶段。所以对于一次控制传输,设备固件必须要正确控制其执行流程,不能颠倒。当收到EP0 SETUP包到达的信息之后,固件要分析其请求的具体内容,这里假定为读取描述符,然后进入数据阶段向主机发送相应描述符的具体内容,发送完成后,进入状态阶段。状态阶段结束后,一次控制传输就此完成。要注意的是,就算是进入各个阶段,也要等待主机发送事务请求后才能响应具体操作。也就是,假定固件分析了EP0 SETUP包得到主机的请求是读取某个描述符,固件随后应该进入数据阶段,但只是流程逻辑上的进入,具体的操作还要等待主机的控制IN令牌到达后,才能开始数据阶段真正的数据传输,之后进入状态阶段。一般地,状态阶段只需设定一个寄存器通知芯片开始状态阶段即可,无需干预其细节。主机对设备的识别最初是通过控制管道来进行的,一系列控制传输(主机识别设备的请求)完成之后,主机就能识别到USB设备了,在设备管理器中会显示出来(但是不一定能完全正常地使用设备,因为可能还有一些协议并未完成,例如Mass Storage设备还需对SCSI命令正确响应,文档的第3部分会有具体讲述)。下面举一个例子说明固件处理控制传输的思路,当然实际应用中并不限于这样的思路。

    这个例子的思路是,在响应USB产生的中断时,会用全局变量记录下中断的发生,然后在主循环里面进行具体处理。

    /* USB服务程序伪代码 */

    void USB_Service(void)

    {   

           /*处理控制传输的3个阶段*/

           switch (EP.EP0.Stage)

           {

                  case C_STAGE_EP0_SETUP:  /*处在建立阶段*/

                         if (!USB_Setup ())  /*如果请求是被支持的*/

                                EP.EP0.Stage = C_STAGE_EP0_DATA;       /*转入数据阶段*/

                         break;

                

                  case C_STAGE_EP0_DATA:  /*处在数据阶段*/

                         if (EP.EP0.Status == C_STATUS_EP0_IN_NACK)  /*收到了IN令牌*/

                         {

                                USB_WriteEP0FIFO();  /*通过控制端点发送数据给主机*/

                                EP.EP0.Status = C_STATUS_RESET;  /*已处理完毕,所以复位此状态*/

                                EP.EP0.Stage = C_STAGE_EP0_STATUS;  /*转入状态阶段*/

                                重新使能EP0_IN_NACK中断;  /*在ISR中会关掉此中断*/

                         }

                         break;

                

                  case C_STAGE_EP0_STATUS:

                         使能EP0_STATUS寄存器;

                         break;

                

                  default:

                         break;

           }

    }

    /*USB中断服务程序伪代码(部分)*/

    void USB_ISR(void)

    {

           if (SETUP包到达)

           {

                  清中断;

                  EP.EP0.Stage = C_STAGE_EP0_SETUP;

                  EP.EP0.Status = C_STATUS_EP0_SETUP_ARRIVAL;

           }

           else if (EP0 IN令牌到达但是芯片自动回复了NAK)

           {

                  清中断;

                  关闭此中断;

                  EP.EP0.Status = C_STATUS_EP0_IN_NACK;

           }

    }

    /*USB控制传输的建立阶段处理程序伪代码*/

    int USB_Setup (void)

    {

           通过各寄存器的值来得到请求的类型和相关数据;

           if (请求类型是读取描述符)

           {

                  switch (描述符值)

                  {

                         case 设备描述符值:

                         将全局的发送数据的指针指向设备描述符buffer;

                         break;

                         ......

                         default: break;

                  }

           }

           else if (设备还需处理的其他请求)

           {

                  处理;

           }

           else  /*不支持的请求*/

           {

                  发送STALL信号;

                  return 1;  /*返回错误*/

           }

           return 0;  /*返回正确*/

    }

    /*通过端点0发送数据*/

    void USB_WriteEP0FIFO(void)

    {

           取得全局的发送数据的指针;

           利用指针读取描述符的数据并填充至端点0的FIFO;

           通知芯片EP0 IN数据包已准备好;

    }

    查看原文


      您阅读这篇文章共花了:  
    二维码加载中...
    本文作者:最爱香茗      文章标题: USB固件开发总结(二)[转载]
    本文地址:http://www.gcsjl8.com/?post=123
    版权声明:若无注明,本文皆为“成长记忆”原创,转载请保留文章出处。