Chinaunix首页 | 论坛 | 博客
  • 博客访问: 97335
  • 博文数量: 12
  • 博客积分: 1400
  • 博客等级: 上尉
  • 技术积分: 485
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-12 22:46
文章分类

全部博文(12)

文章存档

2011年(1)

2009年(11)

我的朋友

分类: 嵌入式

2009-06-21 13:59:25

3.2 固件在USB设备设别阶段的编程思路

一般地,USB设备接口芯片会产生一些中断来通知程序员特定事件的发生。譬如说,EP0(缺省控制端点) SETUP包的到达,EP0 INOUT事务的发生等等。控制传输是分三个阶段的:建立阶段,数据阶段,状态阶段。所以对于一次控制传输,设备固件必须要正确控制其执行流程,不能颠倒。当收到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)

{

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

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

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

}

阅读(3426) | 评论(1) | 转发(10) |
给主人留下些什么吧!~~