STM32 USB学习笔记8

发布者:RadiantRiver最新更新时间:2019-05-29 来源: eefocus关键字:STM32  USB  学习笔记 手机看文章 扫描二维码
随时随地手机看文章

主机环境:Windows 7 SP1


开发环境:MDK5.14


目标板:STM32F103C8T6


开发库:STM32F1Cube库和STM32_USB_Device_Library


现在分析USB器件库核心文件的最后一个文件usbd_ctlreq,该文件提供了标准请求的处理,跟USB2.0协议的第九章节紧密关联。在Setup阶段根据bmRequest字段的内容分为:设备请求、接口请求、端点请求。并根据不同的请求调用不同的函数体,USB2.0协议中定义的标清请求有以下几种



通过第一个竖栏可以看出同一个请求代码可以对应多个接收者,例如CLEAR_FEATURE请求可以是设备请求也可以是接口请求,同样也可以是端点请求。对应的各个请求代码,如下



在usbd_def.h文件中可以找到与之对应的定义,如下:



#define  USB_REQ_GET_STATUS                             0x00

#define  USB_REQ_CLEAR_FEATURE                          0x01

#define  USB_REQ_SET_FEATURE                            0x03

#define  USB_REQ_SET_ADDRESS                            0x05

#define  USB_REQ_GET_DESCRIPTOR                         0x06

#define  USB_REQ_SET_DESCRIPTOR                         0x07

#define  USB_REQ_GET_CONFIGURATION                      0x08

#define  USB_REQ_SET_CONFIGURATION                      0x09

#define  USB_REQ_GET_INTERFACE                          0x0A

#define  USB_REQ_SET_INTERFACE                          0x0B

#define  USB_REQ_SYNCH_FRAME                            0x0C

首先看一下标准设备请求的处理,

/**

* @brief  USBD_StdDevReq

*         Handle standard usb device requests

* @param  pdev: device instance

* @param  req: usb request

* @retval status

*/

USBD_StatusTypeDef  USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef  *req)

{

  USBD_StatusTypeDef ret = USBD_OK;  

  

  switch (req->bRequest) 

  {

  case USB_REQ_GET_DESCRIPTOR: 

    

    USBD_GetDescriptor (pdev, req) ;

    break;

    

  case USB_REQ_SET_ADDRESS:                      

    USBD_SetAddress(pdev, req);

    break;

    

  case USB_REQ_SET_CONFIGURATION:                    

    USBD_SetConfig (pdev , req);

    break;

    

  case USB_REQ_GET_CONFIGURATION:                 

    USBD_GetConfig (pdev , req);

    break;

    

  case USB_REQ_GET_STATUS:                                  

    USBD_GetStatus (pdev , req);

    break;

    

    

  case USB_REQ_SET_FEATURE:   

    USBD_SetFeature (pdev , req);    

    break;

    

  case USB_REQ_CLEAR_FEATURE:                                   

    USBD_ClrFeature (pdev , req);

    break;

    

  default:  

    USBD_CtlError(pdev , req);

    break;

  }

  

  return ret;

}

符合标准的设备请求通过Table 9-3可以看出一共有8种,这里只处理了7种,SET_DESCRIPTOR是没有处理的,当请求不是这7种请求的任何一种时通过USBD_CtlError()函数回应给USB主机一个STALL表明请求错误发生。首先看第一个请求获取描述符请求的处理,如下:


/**

* @brief  USBD_GetDescriptor

*         Handle Get Descriptor requests

* @param  pdev: device instance

* @param  req: usb request

* @retval status

*/

static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev , 

                               USBD_SetupReqTypedef *req)

{

  uint16_t len;

  uint8_t *pbuf;

  

    

  switch (req->wValue >> 8)

  { 

#if (USBD_LPM_ENABLED == 1)

  case USB_DESC_TYPE_BOS:

    pbuf = pdev->pDesc->GetBOSDescriptor(pdev->dev_speed, &len);

    break;

#endif    

  case USB_DESC_TYPE_DEVICE:

    pbuf = pdev->pDesc->GetDeviceDescriptor(pdev->dev_speed, &len);

    break;

    

  case USB_DESC_TYPE_CONFIGURATION:     

    if(pdev->dev_speed == USBD_SPEED_HIGH )   

    {

      pbuf   = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(&len);

      pbuf[1] = USB_DESC_TYPE_CONFIGURATION;

    }

    else

    {

      pbuf   = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(&len);

      pbuf[1] = USB_DESC_TYPE_CONFIGURATION;

    }

    break;

    

  case USB_DESC_TYPE_STRING:

    switch ((uint8_t)(req->wValue))

    {

    case USBD_IDX_LANGID_STR:

     pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev->dev_speed, &len);        

      break;

      

    case USBD_IDX_MFC_STR:

      pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev->dev_speed, &len);

      break;

      

    case USBD_IDX_PRODUCT_STR:

      pbuf = pdev->pDesc->GetProductStrDescriptor(pdev->dev_speed, &len);

      break;

      

    case USBD_IDX_SERIAL_STR:

      pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev->dev_speed, &len);

      break;

      

    case USBD_IDX_CONFIG_STR:

      pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev->dev_speed, &len);

      break;

      

    case USBD_IDX_INTERFACE_STR:

      pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev->dev_speed, &len);

      break;

      

    default:

#if (USBD_SUPPORT_USER_STRING == 1)

      pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue) , &len);

      break;

#else      

       USBD_CtlError(pdev , req);

      return;

#endif   

    }

    break;

  case USB_DESC_TYPE_DEVICE_QUALIFIER:                   

 

    if(pdev->dev_speed == USBD_SPEED_HIGH  )   

    {

      pbuf   = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(&len);

      break;

    }

    else

    {

      USBD_CtlError(pdev , req);

      return;

    } 

 

  case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:

    if(pdev->dev_speed == USBD_SPEED_HIGH  )   

    {

      pbuf   = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(&len);

      pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;

      break; 

    }

    else

    {

      USBD_CtlError(pdev , req);

      return;

    }

 

  default: 

     USBD_CtlError(pdev , req);

    return;

  }

  

  if((len != 0)&& (req->wLength != 0))

  {

    

    len = MIN(len , req->wLength);

    

    USBD_CtlSendData (pdev, 

                      pbuf,

                      len);

  }

  

}

也是一大串switch-case语句,这样的代码虽然多但容易分析,在GET_DESCRIPTOR请求中,根据Table 9-3可知wValue字段的含义是描述符类型和描述符索引,在USB2.0协议的9.4.3章节中可以看到wValue的高字节标记了描述符的类型,wValue的低字节标记了描述符的索引。在USBD_GetDescriptor()函数中首先是检测描述符类型,第一个分支是设备描述符,通过pdev句柄的pDesc指针下的GetDeviceDescriptor指针调用所需要的函数即我们之前分析过的usbd_desc.c文件中的对应函数。第二个分支是获取配置描述符,这个是通过设备类指针获取的,放在后面分析,且这里分出了高速和全速模式。接着一个大分支是获取字符串描述符,这里就需要用到wValue的低字节描述符索引来细分各个字符串描述符,获取字符串描述符的处理跟获取设备描述符类似,不再赘述,索引号错误返回请求错误状态。DEVICE_QUALIFIER和OTHER_SPEED_CONFIGURATION描述符的获取都是在高速模式下才会有,由于STM32F103C8T6只支持全速模式,因此这里不再分析,直接返回请求错误。在最后发送这些数据到USB主机时有判断len和wLenth的大小,且返回的数据长度是两者的最小值,USB2.0协议的9.3.5章节中提到在一个输入请求中设备返回的数据不可以大于wLength字段指示的值,在一个输出请求中wLength字段的值一定是USB主机发出的数据长度值。如下:


至此,描述符的获取分析完毕,返回到标准设备请求函数USBD_StdDevReq()中查看第二个请求设置地址,如下:



/**

* @brief  USBD_SetAddress

*         Set device address

* @param  pdev: device instance

* @param  req: usb request

* @retval status

*/

static void USBD_SetAddress(USBD_HandleTypeDef *pdev , 

                            USBD_SetupReqTypedef *req)

{

  uint8_t  dev_addr; 

  

  if ((req->wIndex == 0) && (req->wLength == 0)) 

  {

    dev_addr = (uint8_t)(req->wValue) & 0x7F;     

    

    if (pdev->dev_state == USBD_STATE_CONFIGURED) 

    {

      USBD_CtlError(pdev , req);

    } 

    else 

    {

      pdev->dev_address = dev_addr;

      USBD_LL_SetUSBAddress(pdev, dev_addr);               

[1] [2] [3]
关键字:STM32  USB  学习笔记 引用地址:STM32 USB学习笔记8

上一篇:STM32 USB学习笔记9
下一篇:STM32 USB学习笔记7

推荐阅读最新更新时间:2024-11-19 12:22

STM32 启动文件选择
简介:STM32 启动文件选择的简单介绍 - startup_stm32f10x_ld_vl.s: for STM32 Low density Value line devices - startup_stm32f10x_ld.s: for STM32 Low density devices - startup_stm32f10x_md_vl.s: for STM32 Medium density Value line devices - startup_stm32f10x_md.s: for STM32 Medium density devices - startup_stm32f10x_hd.s: for
[单片机]
关于STM32的看门狗总结
一、独立看门狗 STM32的独立看门狗有内部的40kHz低速时钟驱动,即使主时钟发生故障,他也仍然有效。需要注意:独立看门狗的时钟是一个内部RC时钟,所以并不是准确的40kHz,而是在30kHz~60kHz之间变化的时钟,所以独立看门狗的时间并不精确。 在键值寄存器(IWDG_KR)中写入0xCCCC,开始启动独立看门狗;此时计数器开始从复位值0xFFF递减计数;当计数到末尾0x000时,会产生一个信号(IWDG_RESET)。无论何时只要键值寄存器(IWDG_KR)中写入0xAAAA,IWDG_RLR中的值就会被重新加载到计数器中去,从而避免产生看门狗复位。 独立看门狗时钟来自内部低速时钟LSI,需使能 RCC_LSICmd(
[单片机]
创建基于固件库的stm32程序模板并实现流水灯
一、准备 Keil mdk514 下载STM32F10x_StdPeriph_Lib_V3.5.0固件库(百度搜索或http://download.csdn.net/detail/weboo10000/9084145). 示例芯片型号:STM32F103C8 二、创建工程 1. 创建工程目录:新建一个文件夹,起名为“Template工程模板”,在该文件夹下建立下图所示子文件夹 图1:工程文件目录结构 2. 准备文件:复制固件库LibrariesSTM32F10x_StdPeriph_Driver下的2个文件夹到工程模板目录的FWLIB下;复制固件库LibrariesCMSISCM3CoreSupport下
[单片机]
创建基于固件库的<font color='red'>stm32</font>程序模板并实现流水灯
STM32 IIC通信之PAJ7620U2手势识别模块驱动程序源码详解
大家好。本人小白一个,最近在自学stm32,想用手势识别模块做一点好玩的,正好借此巩固IIC 通信的内容。 很多人刚刚接触IIC、SPI、CAN等通信方式时都会有一堆的问题:为什么要学它?学它可以做什么?我该怎么去学习它呢?我就在这里和大家分享一下自己学习时的所思所感吧,若有表述不对之处,还请各位大佬指出,我好立刻改正。 话不多说,先上硬货。 一、回答上面的问题: 1、什么是IIC通信呢?简单,两条线通信同步串行总线。(在此不做更多说明) 2、为什么要学习这些看起来“根本没多大用处”的通信协议呢?大哥,你总不能永远靠串口吃饭吧 ,况且真正到了实际项目中,通信的方式要根据环境选择,你总不能想当然的自己决定吧,学好这些通信方式,你
[单片机]
基于STM32设计的四轴飞行器飞控系统
引言 四轴飞行器是一种结构紧凑、飞行方式独特的垂直起降式飞行器,与普通的飞行器相比具有结构简单,故障率低和单位体积能够产生更大升力等优点,在军事和民用多个领域都有广阔的应用前景,非常适合在狭小空间内执行任务。因此四旋翼飞行器具有广阔的应用前景,吸引了众多科研人员,成为国内外新的研究热点。 本设计主要通过利用惯性测量单元(IMU)姿态获取技术、PID电机控制算法、2.4G无线遥控通信技术和高速空心杯直流电机驱动技术来实现简易的四轴方案。整个系统的设计包括飞控部分和遥控部分,飞控部分采用机架和控制核心部分一体设计增加系统稳定性,遥控部分采用模拟摇杆操作输入使操作体验极佳,两部分之间的通信采用2.4G无线模块保证数据稳定传输。飞
[单片机]
基于<font color='red'>STM32</font>设计的四轴飞行器飞控系统
基于STM32的双路信号源及配置平台设计
随着在雷达探测、仪表测量、化学分析等领域研究的不断深入,不仅要求定性的完成目标检测,更加需要往高精度、高分辨率成像的方向发展。一方面,产生频率、幅度灵活可控,尤其是低相位噪声、低杂散的频率源对许多仪器设备起着关键作用。另一方面,电子元器件实际性能参数并非理想以及来存在自外部内部的干扰,大量的误差因素会严重影响系统的准确性。双路参数可调的信号源可有效地对系统误差、信号通道间不平衡进行较调,并且可以产生严格正交或相关的信号,这在弱信号检测中发挥重要作用。为此本文采用双通道DDS方法,以STM32为控制器,完成了一种高分辨率灵活可调的双路信号源电路设计。 1 DDS原理及系统方案 1.1 DDS工作原理 直接数字频率合成(DDS)是一种以
[单片机]
基于<font color='red'>STM32</font>的双路信号源及配置平台设计
stm32 设置systick中断抢先式优先级
最近使用STM32时希望将systick的中断优先级降低,但是CMSIS里给出的例子都是类似 view plain copy NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPrio rity = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_I
[单片机]
<font color='red'>stm32</font> 设置systick中断抢先式优先级
基于USB的便携式硬度计数据通信的实现方法
         O 引言   硬度测量是工业生产,特别是材料加工工业中广泛应用的传统测试技术。便携式硬度计是一种较先进的硬度测试仪器,具有体积小、重量轻、易携带、操作方便等特点,尤其对一些大型、不可拆卸部件或精加工后要求复测硬度的零件的硬度测量特别有用。但由于一般便携式硬度计在硬件和功能等方面存在局限,所以不能满足生产过程中的复杂要求。   基于USB总线的数据通信具有安装方便、可靠性高、数据不易丢失、抗干扰能力强、便于数据传输和处理等优点,随着USB应用日益广泛,已经逐渐成为现代数据传输的主要趋势。   本文设计的便携式硬度计数据通信系统实现方案,将USB通信技术应用到硬度测量过程中,选用Philips公司的PDI
[嵌入式]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved