[其他MCU] LPC1788—USB学习-USB标准请求

[复制链接]
3033|17
 楼主| Beckham_Owen 发表于 2015-12-29 20:34 | 显示全部楼层 |阅读模式
开发环境:集成开发环境µVision4 IDE版本4.60.0.0
主机系统:Microsoft Windows XP
开发平台:旺宝悍马1788开发板

第一篇;在中断里复位USB设备
上次触发了EP_SLOW中断,说明端点接收到了数据。再讲端点的数据前,还要说一下在触发EP_SLOW中断前还有个设备中断号0x00000019转换成二进制“11001”,就像我们之前说的,第3位(按照人的逻辑是第4位),这一位是在USB总线复位、USB挂起改变或者连接改变时会置位。以前我们还说,当把设备插入主机时主机会对设备复位。中断号的,第4位,是命令代码寄存器(USBCmdCode)为空(可写入新的命令)。我们就写一个设备状态命令命令号为“FE”命令定义#define CMD_SET_DEV_STAT 0x00FE0500,“05”为命令,然后在读出命令数据命令号也为“FE”命令定义#define DAT_GET_DEV_STAT 0x00FE0200“02”为读,看到底要让我们干嘛,代码如下。

 楼主| Beckham_Owen 发表于 2015-12-29 20:35 | 显示全部楼层
  1. /**********************************************************************
  2. 函数功能;USB中断函数
  3. 函 数 名;USB_IRQHandler
  4. 函数参数;无
  5. 函数返回;无
  6. 作          者:        旺宝电子科技有限公司
  7. ***********************************************************************/
  8. void USB_IRQHandler (void)
  9. {
  10.   uint32_t disr, val;
  11.   uint32_t episr;
  12.   disr = LPC_USB->DevIntSt;      //读设备中断状态
  13.         #if PRINTF
  14.                 _DBG_("中断号");
  15.                 _DBH32(disr);
  16.                 _DBG_("\r\n");
  17.         #endif        
  18.   if (disr & DEV_STAT_INT) {                        /*判断是否有复位、连接发
  19. 生改变、挂起和恢复的中断*/

  20. LPC_USB->DevIntClr = DEV_STAT_INT;        //清除复位、挂起、链接中断

  21. WrCmd(CMD_SET_DEV_STAT);                        /*写一个设置设备状态,05
  22. 命令,准备获得设备状态*/
 楼主| Beckham_Owen 发表于 2015-12-29 20:35 | 显示全部楼层
  1. val = RdCmdDat(DAT_GET_DEV_STAT);    //读命令数据,读取设备状态
  2.                 #if PRINTF
  3.                         _DBG_("设备状态号");
  4.                         _DBH32(val);
  5.                         _DBG_("\r\n");
  6.                 #endif               
  7.     if (val & DEV_RST){                //判断复位
  8.       USB_Reset();
  9.                         #if PRINTF
  10.                         _DBG_("复位\r\n");
  11.                         #endif        
  12.     }
  13.     if (val & DEV_SUS_CH) {            //判断挂起和恢复
  14.       if (val & DEV_SUS) {             //挂起
  15.         USB_Suspend();
  16.                                 #if PRINTF
  17.                                 _DBG_("挂起\r\n");
  18.                                 #endif        
  19.       }
 楼主| Beckham_Owen 发表于 2015-12-29 20:36 | 显示全部楼层
  1. else {                     //恢复
  2.         USB_Resume();
  3.                                 #if PRINTF
  4.                                 _DBG_("恢复\r\n");
  5.                                 #endif        
  6.       }
  7.     }
  8.   }
 楼主| Beckham_Owen 发表于 2015-12-29 20:37 | 显示全部楼层
上面的程序有两个函数一个是USB_Suspend();函数挂起,一个是USB_Resume();函数恢复这两个都是空函数不用管它,而复位函数也就是我们以前讲的复位函数也不用分析。现在把程序下载到开发板运行会在串口调试助手里看到以下内容。
*******************************************************************************
Hello NXP Semiconductors
USB2 Decice
         - MCU: LPC17xx
         - Core: ARM CORTEX-M3
         - UART Communication: 115200 bps
This example used to test USB2 Decice
*******************************************************************************
地址
0x00
中断号
0x00000019
设备状态号
0x0000000D
挂起
中断号
0x00000039
设备状态号
0x00000019
地址
0x00
复位
恢复
中断号
0x00000015
 楼主| Beckham_Owen 发表于 2015-12-29 20:38 | 显示全部楼层
现在的中断号是0x00000015转换为二进制“10101”,产生的中断是:                        
1、每隔1ms 产生一次帧中断。
2、端点的慢速中断。
3、命令代码寄存器(USBCmdCode)为空。
和刚才的“11001”中断号少了一个让我们复位的过程,转而多一个端点慢速中断,在前面我们说了,有了端点慢速中断说明,端点里有数据。到底是哪一个端点,端点里又有什么数据!现在就要用到端点中断状态寄存器(USBEpintST)。
 楼主| Beckham_Owen 发表于 2015-12-29 20:39 | 显示全部楼层
2015-6-17 15:03 上传
下载附件 (135.29 KB)

第二篇;读端点0数据

 楼主| Beckham_Owen 发表于 2015-12-29 20:39 | 显示全部楼层
在读端点数据时先要判断主机发给端点的这一帧数据是要让设备干嘛的,先要向前面说的,读一下命令数据寄存器看要让设备干嘛。代码就在原来的中断函数里加入。定义的读端点命令数据为#define DAT_SEL_EP(x)  (0x00000200 | ((x) << 16))  //选择第x个端点读。02为读。
  1. if (disr & EP_SLOW_INT) {                                 //端点的慢速中断
  2. episr = LPC_USB->EpIntSt;                                //读端点中断状态
  3.   LPC_USB->EpIntClr = episr;                        //清除读到的端点中断。
  4.         #if PRINTF
  5.                 _DBG_("读端点中断");
  6.                 _DBH32(episr);
  7.                 _DBG_("\r\n");
  8.         #endif
  9.           val = RdCmdDat(DAT_SEL_EP(episr));//读episr端点的命令数据。
  10. #if PRINTF
  11.         _DBG_("命令数据");
  12.         _DBH32(val);
  13.         _DBG_("\r\n");
  14. #endif
  15. if(val & EP_SEL_F){                        //如果命令位FE置位表示OUT端点
  16.    if(1 == episr){
  17.         if(val & EP_SEL_STP){                //判断是否为SETUP(控制传输)令牌包。
  18.                 USB_EndPoint0(USB_EVT_SETUP);        //让端点0处理SETUP(控制传输)包。        
  19.                                 }
  20.        }


 楼主| Beckham_Owen 发表于 2015-12-29 20:41 | 显示全部楼层
  1. else{
  2.                 }
  3. }
  4. else{                                        //如果命令位FE为0表示IN端点

  5. }
  6. LPC_USB->DevIntClr = EP_SLOW_INT;        //清除端点慢速中断
  7. }


实验现象如图(321)。
2015-6-17 15:03 上传
下载附件 (31.95 KB)

图321


 楼主| Beckham_Owen 发表于 2015-12-29 20:42 | 显示全部楼层
现在我们读到的端点中断时0x00000001,转换二进制“0000 0000 0000 0000 0000 0000 0000 0001”说明是端点0中断。前面说,逻辑端点0是控制传输,产生中断的是逻辑端点里的物理端点0,也就是OUT(输出)端点0。读到的命令数据是0x00000025,现在转换为二进制我们就转换25为“100101”。



 楼主| Beckham_Owen 发表于 2015-12-29 20:43 | 显示全部楼层
从数据手册上的说明,可以看出来端点缓冲区的这帧数据是要干嘛用的。中断的第0位大概意思是说,该位置位,对于OUT 端点,有一个端点读缓冲区是满的。第2位的大概意思是说,该位置位,所选端点接收到的包为SETUP 令牌包。SETUP令牌是通知设备将要开始一次控制传输。

在USB的协议中,规定了有8字节的标准设备请求,用来对设备枚举过程进行控制。这8个字节是一次性接收到的,所以端点的大小不能小于8字节的空间。前面我们设置端点0的大小为16字节,用来接收肯定是够了。接收到的这8个字节在枚举过程中会不断的出现,去控制设备返回给主机的信息也就以后所要说的描述符,这些描述符就会描述一个设备的属性让主机能够加载自身的驱动去驱动枚举好的设备。下面我们就来说一下标准设备请求的结构和作用如表(3—2—2)。

 楼主| Beckham_Owen 发表于 2015-12-29 20:44 | 显示全部楼层
表(3—2—2)USB标准设备请求数据结构
偏移量(字节)
大小(字节)
取值
描述
0
bmRequestType
1
位图
D7:数据传输方向
   0—主机到设备
   1—设备到主机
D5~6:请求类型
   0—标准
   1—类
   2—厂商
   3—保留
D0~4:请求连接者
   0—设备
   1—接口
   2—端点
   3—其他
   4~31—保留
1
bRequest
1
数值
请求代码
2
wValue
2
数值
该域意义由具体请求决定
4
wIndex
2
索引或偏移量
该域意义由具体请求决定
6
wLength
2
字节数
数据过程所需要的数据长度


 楼主| Beckham_Owen 发表于 2015-12-29 20:45 | 显示全部楼层
在表中我们看到有项是“域”的这个东西。在USB里数据是按包来传输数据的,而包的由域组成的。域就是USB传输中的最小单位。前面说了,端点0里有数据现在就把数据读出来看到的是些啥数据。我们先要定义一个结构体来接收这个标准请求。
  1. /*USB标准设备请求结构体*/
  2. typedef __packed struct _USB_SETUP_PACKET {        //这个结构体的“__packed ”
  3. __packed        union {
  4.                         uint8_t B;
  5.                         __packed struct{
  6.                                 uint8_t Recipient  : 5;                //请求的接收者
  7.                                 uint8_t Type      : 2;        //请求类型
  8.                                 uint8_t Dir       : 1;                //数据传输方向
  9.                         } BM;
  10. } bmRequestType;                                                //请求的特性
  11.         uint8_t  bRequest;                                        //请求代码        


 楼主| Beckham_Owen 发表于 2015-12-29 20:46 | 显示全部楼层
  1. __packed        union {
  2.                 uint16_t W;
  3.                 __packed struct {
  4.                         uint8_t L;
  5.                         uint8_t H;                                
  6.                 } WB;
  7. } wValue;                                                        //该域意义由具体请求决定

  8. __packed        union {
  9.                 uint16_t W;
  10.                 __packed struct {
  11.                         uint8_t L;
  12.                         uint8_t H;
  13.                 } WB;
  14. } wIndex;                                        //该域意义由具体请求决定
  15. uint16_t      wLength;                //需要传输的字节数
  16. } USB_SETUP_PACKET;
 楼主| Beckham_Owen 发表于 2015-12-29 20:47 | 显示全部楼层
利用这个结构体我们把就收到的数据传给它,以后在用的时候就方便多了。现在还要一个接收来自端点数据的函数,代码如下:
  1. /**********************************************************************
  2. 函数功能;读USB端点数据函数
  3. 函 数 名;USB_ReadEP
  4. 函数参数;EPNum;要读的端点。
  5.                 *pData;指向缓冲区的指针。
  6. 函数返回;读到的字节数。
  7. 作         者:        旺宝电子科技有限公司
  8. ***********************************************************************/
  9. #define PKT_LNGTH_MASK      0x000003FF
  10. #define CTRL_RD_EN          0x00000001
  11. #define CTRL_WR_EN          0x00000002
  12. uint32_t USB_ReadEP (uint32_t EPNum, uint8_t *pData)
  13. {
  14.   uint32_t cnt, n;

  15.   LPC_USB->Ctrl = ((EPNum & 0x0F) << 2) | CTRL_RD_EN;        /*Crtl寄存器是控制端点读写的寄存
  16.                                                                                                 器,端点号EPNum上移两位的原因是
  17.                                                                                                 低两位是读写控制位。*/
  18.   do {
  19.     cnt = LPC_USB->RxPLen;      
 楼主| Beckham_Owen 发表于 2015-12-29 20:48 | 显示全部楼层
  1. } while ((cnt & (1<<11)) == 0);                                                        //检查接收到的长度字段是否正确。
  2.   cnt &= PKT_LNGTH_MASK;                                                        //提取接收到的字节长度信息。
  3.   for (n = 0; n < (cnt + 3) / 4; n++) {                                                //开始循环读数据
  4.     *((__packed uint32_t *)pData) = LPC_USB->RxData;
  5.     pData += 4;
  6.   }
  7.   LPC_USB->Ctrl = 0;                                                                //禁止向端点读写

  8.   return (cnt);
  9. }

在端点0的数据都是控制传输,所以要做的工作比较多我们就再建一个函数来专对端点0的控制传输数据进行相应的操作,现在我们的目的是先把数据打印出来再说,所以现在不用过多的处理。
wangjakn 发表于 2016-4-29 16:41 | 显示全部楼层
1021568988 发表于 2018-1-6 13:48 | 显示全部楼层
楼主咋不继续更新了呢?期待。。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

32

主题

234

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部