历史上的今天
返回首页

历史上的今天

今天是:2024年11月09日(星期六)

正在发生

2020年11月09日 | 基于STM32的USB程序开发笔记(四)——USB设备的枚举(上)

2020-11-09 来源:eefocus

USB设备能否工作,枚举步骤,用“乡村爱情”里的话说,“必须的!”,网上也有很多资料,圈圈就提供了一份详细的枚举过程,但对STM32是怎么响应的没有说明,一会详细道来,先上圈圈的提供的那个枚举图示,希望圈圈支持,如果不妥,请与我联系,谢谢。 

我将此转换成了PDF文件,方便查看。

首先说明一个变量,定义在usb_core.c中: 

volatile DEVICE_INFO vsDeviceInfo; 

看意思就知道他的作用了,DEVICE_INFO是个结构,定义在usb_type.h中: 

// ***************************************************************************** 

// DEVICE_INFO 

// ***************************************************************************** 

typedef struct _DEVICE_INFO 

  unsigned char bDeviceAddress; 


  unsigned char bCurrentFeature; 

  unsigned char bCurrentConfiguration; 

  unsigned char bCurrentInterface; 

  unsigned char bCurrentAlternateSetting; 


  WORD_2BYTE    uStatusInfo; 


  DEVICE_STATE  eDeviceState; 

  RESUME_STATE  eResumeState; 

  CONTROL_STATE eControlState; 


  SETUP_DATA    SetupData; 


  TRANSFER_INFO TransInfo; 

DEVICE_INFO, 

*PDEVICE_INFO; 


在枚举过程中,就是如何处理好SETUP事件,如果STM32 USB接收到正确的SETUP事件,将响应函数CTR_SETUP0(),SETUP事件是特殊的OUT事件,数据方向 Host->Device,SETUP事件数据长度固定为8,数据定义在DEVICE_INFO.SetupData,其数据结构是(定义在 usb_type.h中): 

typedef struct _SETUP_DATA 

  unsigned char bmRequestType;            // request type 

  unsigned char bRequest;                 // request code 


  WORD_2BYTE wValue; 

  WORD_2BYTE wIndex; 

  WORD_2BYTE wLength; 

SETUP_DATA, 

*PSETUP_DATA; 


WORD_2BYTE是定义的一个共用体: 

typedef union _WORD_2BYTE 

  unsigned short w; 

  struct 

  { 

    unsigned char LSB; 

    unsigned char MSB; 

  }b; 

WORD_2BYTE; 


为什么将SETUP数据结构中的wValue,wIndex,wLength如此定义? 

1:USB协议中所有数据传输都是依照低位在先的原则 

2:高地位字节可能功能复用 

这样在后续的程序编写中就变得十分方便,ST提供的USB固件方法同样如此,但这方面的处理让人有些摸不着头脑,详情可参阅。至于具体的SETUP数据结构含义如何,还是要具备基本知识:了解USB协议 


CTR_SETUP0() 函数将SETUP数据提取出来,SETUP数据结构有0长度和非0长度的数据结构,详细参阅USB2.0官方协议第9章。在这将两种区别开来分别执行 SETUP0_NoData()和SETUP0_Data()函数,并返回结果,根据返回结果再响应USB主机 

// ***************************************************************************** 

// Function Name  : CTR_SETUP0 

// Description    : 

// Input          : 

// Output         : 

// Return         : 

// ***************************************************************************** 

void CTR_SETUP0(void) 

  RESULT eResult; 


  BufferCopy_PMAToUser( (unsigned char *)&vsDeviceInfo.SetupData, 

                        GetBuffDescTable_RXAddr(ENDP0), 

                        GetBuffDescTable_RXCount(ENDP0)); 


  if(vsDeviceInfo.SetupData.wLength.w == 0) 

  { 

    eResult = SETUP0_NoData(); 

  } 

  else 

  { 

    eResult = SETUP0_Data(); 

  } 


  switch(eResult) 

  { 

  case RESULT_SUCCESS: 


    break; 


  case RESULT_LASTDATA: 


    break; 


  case RESULT_ERROR: 

  case RESULT_UNSUPPORT: 

    SetEPR_RXStatus(ENDP0, EP_RX_VALID); 

    SetEPR_TXStatus(ENDP0, EP_TX_STALL); 

    break; 

  } 


SETUP0_Data() 和SETUP0_NoData()函数支持的所有USB请求类型只有罗列的这些,有多少种组合都定义在USB协议中,程序根据请求代码,再去执行对应函数,这样做的目的就是让程序结构明了。其中注释为"// done"的部分表明此部分功能已完成。对于未完成部分,希望大家在交流中完善。 


// ***************************************************************************** 

// Routine Groups: SETUP_Data 

// ***************************************************************************** 

RESULT SETUP0_Data(void) 

  // SetupData.bRequest: request code 

  switch(vsDeviceInfo.SetupData.bRequest) 

  { 

  case SR_GET_STATUS:         return SR_GetStatus();                  // done 

  case SR_GET_DESCRIPTOR:     return SR_GetDescriptor();              // done 

  case SR_SET_DESCRIPTOR:     return SR_SetDescriptor();              // unsupport 

  case SR_GET_CONFIGURATION:  return SR_GetConfiguration();           // done 

  case SR_GET_INTERFACE:      return SR_GetInterface();               // unsupport 

  case SR_SYNCH_FRAME:        return SR_SynchFrame();                 // unsupport 


  default: return RESULT_UNSUPPORT; 

  } 


// ***************************************************************************** 

// Routine Groups: SETUP_NoData 

// ***************************************************************************** 

RESULT SETUP0_NoData(void) 

  // SetupData.bRequest: request code 

  switch(vsDeviceInfo.SetupData.bRequest) 

  { 

  case SR_CLEAR_FEATURE:      return SR_ClearFeature();        // unsupport 

  case SR_SET_FEATURE:        return SR_SetFeature();          // unsupport 

  case SR_SET_ADDRESS:        return SR_SetAddress();          // done 

  case SR_SET_CONFIGURATION:  return SR_SetConfiguration();    // done 

  case SR_SET_INTERFACE:      return SR_SetInterface();        // unsupport 


  default: return RESULT_UNSUPPORT; 

  } 

}


推荐阅读

史海拾趣

Eurofarad公司的发展小趣事

Eurofarad始终将技术创新作为公司发展的核心动力。随着科技的不断进步,Eurofarad不断投入研发资源,推动电子元件技术的创新。公司成功研发出了一系列具有创新性的产品,如陶瓷电容器、塑料薄膜电容器、云母电容器等。这些产品不仅具有更高的性能和更长的使用寿命,而且更符合市场的需求,为Eurofarad赢得了更多的市场份额。

Don Connex Electronics Co Ltd公司的发展小趣事

Don Connex Electronics Co Ltd成立于上世纪90年代初,当时电子行业正处于快速发展阶段。公司的创始人李明凭借其在半导体领域的深厚技术背景,带领团队研发出了一款高性能的电源管理芯片,这款芯片在业界引起了广泛关注。该芯片以其低功耗、高效率的特性,迅速在市场上打开了局面,为公司的初创阶段奠定了坚实的基础。

Data Delay Devices公司的发展小趣事

企业文化是企业的灵魂和核心竞争力之一。DDD公司一直注重企业文化的建设和发展。公司倡导“创新、协作、务实、进取”的企业精神,鼓励员工勇于创新、敢于担当、追求卓越。同时,DDD公司还注重员工培训和福利待遇的改善,为员工提供了广阔的发展空间和良好的工作环境。这种积极向上的企业文化氛围使得DDD公司成为了一个充满活力和凝聚力的团队。

ABCO公司的发展小趣事

在技术创新的基础上,ABCO公司开始积极拓展市场。公司通过与大型电子设备制造商建立合作关系,将产品应用于汽车、医疗、工业等多个领域。同时,ABCO公司还加强了品牌建设,通过参加国际电子展会、举办技术研讨会等方式,提升了品牌知名度和影响力。

Dean Technology公司的发展小趣事

近年来,随着电子行业的快速发展和市场竞争的加剧,Dean Technology公司也面临着前所未有的挑战。为了应对这些挑战,公司积极调整战略方向,加强内部管理和团队建设。同时,他们还密切关注行业趋势和市场需求的变化,及时调整产品结构和市场策略。这些努力使得Dean Technology在应对行业变革和挑战时更加从容和自信。

请注意,以上故事是基于对Dean Technology公司一般情况的了解而编写的,可能不完全符合公司的实际发展历程。如需更详细的信息,请查阅相关资料或联系公司官方渠道。

ARBOR公司的发展小趣事

随着环保意识的日益增强,ARBOR公司积极响应国家号召,致力于绿色电子产品的研发和生产。公司投入大量资金研发环保材料和技术,成功推出了一系列绿色电子产品。这些产品不仅具有优异的性能,还符合环保标准,得到了消费者的广泛认可。ARBOR公司的绿色环保理念也为整个电子行业树立了榜样。

问答坊 | AI 解惑

基于AT91RM9200+CPLD高速大缓存AD采集方案

恒颐AT91RM9200+CPLD高速大缓存AD采集方案 北京恒颐高科技术有限公司 Beijing Hengyi Embedded System Co.,ltd. 『恒颐高速数据采集产品图』 数据采集系统在工业测控、环境监测等方面的应用非常广泛。随着科学技术的发展,数据采集技术 ...…

查看全部问答>

开关电源变压器铁芯磁滞回线测量-part2开关电源原理与设计(连载60)

从原理上来说,只有RC积分电路输出电压的特性与磁场强度取样电路输出电压的特性(速率)基本一致的时候,磁滞回线的显示失真才会最小。那么u1电压的变化特性与u2电压的变化特性是否基本一致呢?为了简单和便于分析,这里我们把输入电压看成是交流脉 ...…

查看全部问答>

一个LPC2132的中断很傻的问题

#include void __irq IRQ_TIMER0(void) {         T0IR = 0X01;         VICVectAddr = 0X00;        } int main(void) {         VICIntSelect = 0X0 ...…

查看全部问答>

求教:嵌入式手机驱动是做什么的

http://campus.chinahr.com/2010/pages/mediatekbj/jobs.asp 看看这个网页 我是做手机驱动与系统开发的 主要是做什么的?迷茫...…

查看全部问答>

wince 5.0 3G如何拨号上网?和GPRS拨号上网有区别吗?

wince 5.0 3G如何拨号上网?和GPRS拨号上网有区别吗?以前在WINCE 5.0是通过GPRS拨号上网的。现在要改为3G了,但是拨号拨不上去?怎么回事?高手指点啊。…

查看全部问答>

EmbestIDE出现"parse error"错误提示

编译的时候出现: “/cygdrive/d/EmbestIDE/Build/xgcc-arm-elf/bin/arm-elf-ld:.\\ldscript.ld:3: parse error” 然后双击它找错误就会提示: “E:\\cygdrive\\d\\EmbestIDE\\Build\\xgcc-arm-elf\\bin\\arm-elf-ld:.\\ldscript.ld:3中包含 ...…

查看全部问答>

libero 最新版安装开发流程

这篇文章从网看发现的,不敢独享拿出共享。   Actel的最新开发环境,我着磨两三天,今天终于装上了。   在附件里:   没安的朋友看看吧,再也不用注册发愁啦   …

查看全部问答>

高带宽、高幅值峰值检测电路

本帖最后由 paulhyde 于 2014-9-15 03:20 编辑 图中的三极管用来定时放电,电路中可以不焊接, 我还有一个疑惑,就是两个27K电阻是用来作为电压补偿的,但是我在测试时没有27K电阻发现去掉电阻没有什么关系,求解释    …

查看全部问答>

请问:(stm32),tim_period& TIM_PrescalerConfig的区别与应用,如何理解??

TIM_Period   设置了在下一个更新事件装入活动的自动重装载寄存器周期的值。它的取值必须在0x0000和 0xffff之间。 TIM_Prescaler   设置了用来作为TIMx时钟频率除数的预分频值。它的取值必须在0x0000和0xFFFF之间。 但是 ...…

查看全部问答>