历史上的今天
返回首页

历史上的今天

今天是:2024年10月29日(星期二)

正在发生

2020年10月29日 | STM32 usb_prop.c文件分析与usb_core.h一些数据定义分析

2020-10-29 来源:eefocus

usb_prop.c文件可以说是一个蛮重要的文件,因为USB的许多处理函数都在这里定义。在无论是在USB的建立阶段、数据阶段还是状态阶段的一些处理都在这个文件,USB标准函数请求的函数也在这个文件里。


usb_prop.c一开始就是一连串的结构体,如下:

DEVICE Device_Table =

{

    EP_NUM,    //被使用的端点数

    1    //可以使用的端点数

};


DEVICE_PROP Device_Property = //注册一些CustomHID函数

{

    CustomHID_init, //CustomHID的初始化函数

    CustomHID_Reset, //CustomHID的复位函数

    CustomHID_Status_In, //CustomHID状态输入函数

    CustomHID_Status_Out, //CustomHID状态输出函数

    CustomHID_Data_Setup, //CustomHID的处理有数据阶段的特殊类请求函数

    CustomHID_NoData_Setup, //CustomHID的处理没有数据阶段特殊类请求函数

    CustomHID_Get_Interface_Setting, //CustomHID获取接口及备用接口设置(是否可用)  

    CustomHID_GetDeviceDescriptor, //CustomHID获取设备描述符

    CustomHID_GetConfigDescriptor, //CustomHID获取配置描述符

    CustomHID_GetStringDescriptor, //CustomHID获取字符串描述符

    0, //当前库未使用

    0x40 /*MAX PACKET SIZE*/     //最大的包长度为64字节

};


/*注册USB标准请求的实现函数*/

USER_STANDARD_REQUESTS User_Standard_Requests =

{

    CustomHID_GetConfiguration, //获取配置请求

    CustomHID_SetConfiguration, //设置配置请求

    CustomHID_GetInterface, //获取接口请求

    CustomHID_SetInterface, //设置接口请求

    CustomHID_GetStatus, //获取状态请求

    CustomHID_ClearFeature, //清除属性请求

    CustomHID_SetEndPointFeature, //设置端点属性请求

    CustomHID_SetDeviceFeature, //设置设备属性请求

    CustomHID_SetDeviceAddress //设置设备地址请求

};


/*注册设备描述符信息*/

ONE_DESCRIPTOR Device_Descriptor =  

{

    (uint8_t*)CustomHID_DeviceDescriptor, //注册设备描述符数组

    CUSTOMHID_SIZ_DEVICE_DESC   //设备描述符的长度

};


/*注册设备描述符信息*/

ONE_DESCRIPTOR Config_Descriptor =

{

    (uint8_t*)CustomHID_ConfigDescriptor, //注册配置描述符数组

    CUSTOMHID_SIZ_CONFIG_DESC   //配置描述符的长度

};


/*注册报告描述符信息*/

ONE_DESCRIPTOR CustomHID_Report_Descriptor =

{

    (uint8_t *)CustomHID_ReportDescriptor, //注册报告描述符数组

    CUSTOMHID_SIZ_REPORT_DESC    //报告描述符的长度

};


/*注册HID描述符信息*/

ONE_DESCRIPTOR CustomHID_Descriptor =

{

    (uint8_t*)CustomHID_ConfigDescriptor + CUSTOMHID_OFF_HID_DESC, //注册HID描述符数组

    CUSTOMHID_SIZ_HID_DESC    //HID数组的长度

};


/*注册字符串描述符,包括语言ID、厂商、产品、序列号描述符*/

ONE_DESCRIPTOR String_Descriptor[4] =

{

    {(uint8_t*)CustomHID_StringLangID, CUSTOMHID_SIZ_STRING_LANGID},//注册语言字符串描述符数组

    {(uint8_t*)CustomHID_StringVendor, CUSTOMHID_SIZ_STRING_VENDOR},//注册厂商字符串描述符数组

    {(uint8_t*)CustomHID_StringProduct, CUSTOMHID_SIZ_STRING_PRODUCT},//注册产品字符串描述符数组

    {(uint8_t*)CustomHID_StringSerial, CUSTOMHID_SIZ_STRING_SERIAL} //注册序列号字符串描述符数组

};


应该看了很明白,这一系列的结构体就是注册一些处理函数。我们一个个分析。

先来说下 DEVICE Device_Table这个结构体,DEVICE这个结构体类型在usb_core.h中定义:

typedef struct _DEVICE

{

  uint8_t Total_Endpoint;     /*被使用的端点数*/

  uint8_t Total_Configuration;/*还可以用的端点数*/

}

DEVICE;


这个结构体类型很简单,在结构体中定义了已经被使用的端点和没有被使用的端点,把他们两个放在一起方便查询和管理。




接下去的说说 D EVICE_PROP  Device_Property 这个类型的结构体。这个结构体的前10个元素都是函数指针类型的,把一些常用的函数放在这里,而函数定义都在该结构体之后定义,有没有觉得像是语文中的关键句,把整个文件的概要全部浓缩在这个结构体中了,只要看这个结构体就可以把整个文件做什么了解个七七八八了。这样的结构使用起来也非常方便,比如说我想要使用 CustomHID_init函数,只要写Device_Property.CustomHID_init不就可以了。我们必须学会这种方法。

D EVICE_PROP这个结构体类型还是在usb_core.h中定义:

typedef struct _DEVICE_PROP

{

  void (*Init)(void);        /*初始化设备*/

  void (*Reset)(void);       /*复位该设备*/


  /*在控制传输中分三个过程:1.建立过程,2、可选的数据过程,3、状态过程*/

  /* Device dependent process after the status stage */

  void (*Process_Status_IN)(void);/*状态过程中,处理IN令牌包*/

  void (*Process_Status_OUT)(void);/*状态过程中,处理OUT令牌包*/


  /*在建立阶段的过程中,会有很多特殊类请求的数据阶段stage */

  /*所有在数据阶段的特殊类请求都在Class_Data_Setup()函数中处理

   Class_Data_Setup() 会响应去检查所有的特殊类请求,同时根据请求填充ENDPOINT_INFO结构信息

如果IN令牌包是期望的令牌包,则wLength和wOffset两个域会分别被填充成要发送的总字节数和要开始传输的位置 

如果OUT令牌包是期盼的令牌包,则rLength和rOffser将会分别被填充成要接收的总字节数和要接收数据的缓冲区起始地址

    如果请求有效,Class_Data_Setup返回SUCCESS,否则返回UNSUPPORT


    注意:

因为GET_CONFIGURATION和GET_INTERFACE两个请求跟个别的类联系密切,所以他们会在该函数中检查和处理*/

  RESULT (*Class_Data_Setup)(uint8_t RequestNo);


  /*在建立过程中,会有很多特殊类请求的无数据阶段*/

  /*所有的没有数据阶段的特殊请求都在Class_NoData_Setup这个函数中处理 

   Class_NoData_Setup() 

   会响应去检查所有特殊类请求,并且执行请求

   注意:

   因为SET_CONFIGURATION和SET_INTERFACE这两个请求跟个别的类联系密切,他们都会在该函数中被检查和处理*/

  RESULT (*Class_NoData_Setup)(uint8_t RequestNo);


  /*Class_Get_Interface_Setting()

   这个函数时在usb_core.c文件中被调用来测试应用程序是否支持被选中的接口和备用接口

   这个函数时由用户写的。如果应用程序支持接口和备用接口,则必须返回"SUCCESS",否则,返回"UNSUPPORT"*/


  RESULT  (*Class_Get_Interface_Setting)(uint8_t Interface, uint8_t AlternateSetting);


  uint8_t* (*GetDeviceDescriptor)(uint16_t Length);

  uint8_t* (*GetConfigDescriptor)(uint16_t Length);

  uint8_t* (*GetStringDescriptor)(uint16_t Length);


  /* 这个字段不是用于当前库版本。它是只保持兼容以前的版本*/

  void* RxEP_buffer;

   

  uint8_t MaxPacketSize;


}DEVICE_PROP;





接下去是USER_STANDARD_REQUESTS User_Standard_Requests这个结构体,在这个结构体中主要注册了USB标准请求的实现函数,当然这些函数也实在该结构体后面定义的。跟上面的 D EVICE_PROP  Device_Property结构体类似,就不多讲了。

USER_STANDARD_REQUESTS  结构体也是在usb_core.h中定义:

typedef struct _USER_STANDARD_REQUESTS

{

  void (*User_GetConfiguration)(void);       /*获取配置*/

  void (*User_SetConfiguration)(void);       /*设置配置*/

  void (*User_GetInterface)(void);           /*获取接口*/

  void (*User_SetInterface)(void);           /*设置接口*/

  void (*User_GetStatus)(void);              /*获取状态*/

  void (*User_ClearFeature)(void);           /*清除特性*/

  void (*User_SetEndPointFeature)(void);     /*设置端点特性*/

  void (*User_SetDeviceFeature)(void);       /*设置设备特性*/

  void (*User_SetDeviceAddress)(void);       /*设置设备地址*/

}

USER_STANDARD_REQUESTS;



像ONE_DESCRIPTOR Device_Descriptor、ONE_DESCRIPTOR Config_Descriptor、ONE_DESCRIPTOR CustomHID_Report_Descriptor、ONE_DESCRIPTOR CustomHID_Descriptor、ONE_DESCRIPTOR String_Descriptor[4]这些结构体都不仔细讲了。贴出各个结构体的定义,依旧在usb_core.h中:

typedef struct OneDescriptor

{

  uint8_t *Descriptor;

  uint16_t Descriptor_Size;

}

ONE_DESCRIPTOR, *PONE_DESCRIPTOR;



接下去上面各个结构体注册的函数贴出来:

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

* Function Name  : CustomHID_init.

* Description    : CustomHID Mouse init routine.初始化

* Input          : None.

* Output         : None.

* Return         : None.

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

void CustomHID_init(void)

{


  /* Update the serial number string descriptor with the data from the unique

  ID*/

  Get_SerialNum(); //获取序列号


  pInformation->Current_Configuration = 0;

  /* Connect the device */

  PowerOn(); //上电


  /* Perform basic device initialization operations */

  USB_SIL_Init(); //执行基本的初始化操作,比如说设备IP和端点0的初始化


  bDeviceState = UNCONNECTED;  //设置状态为未连接

}


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

* Function Name  : CustomHID_Reset.

* Description    : CustomHID Mouse reset routine.复位

* Input          : None.

* Output         : None.

* Return         : None.

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

void CustomHID_Reset(void)

{

  /* Set CustomHID_DEVICE as not configured */

  pInformation->Current_Configuration = 0; //设置当前的配置为0,表示没有配置过

  pInformation->Current_Interface = 0;//默认的接口


  /* Current Feature initialization */

  pInformation->Current_Feature = CustomHID_ConfigDescriptor[7];//当前的属性,bmAttributes:设备的一些特性,0xc0表示自供电,不支持远程唤醒


#ifdef STM32F10X_CL   

  /* EP0 is already configured in DFU_Init() by USB_SIL_Init() function */

  

  /* Init EP1 IN snd EP1 OUT as Interrupt endpoint */

  OTG_DEV_EP_Init(EP1_IN, OTG_DEV_EP_TYPE_INT, EP1_SIZE);

  OTG_DEV_EP_Init(EP1_OUT, OTG_DEV_EP_TYPE_INT, EP1_SIZE);

#else 


  SetBTABLE(BTABLE_ADDRESS);


  /* Initialize Endpoint 0 */

  SetEPType(ENDP0, EP_CONTROL);   //设置端点1为控制端点

  SetEPTxStatus(ENDP0, EP_TX_STALL);  //设置端点0发送延时

  SetEPRxAddr(ENDP0, ENDP0_RXADDR);   //设置端点0的接收缓冲区地址

  SetEPTxAddr(ENDP0, ENDP0_TXADDR);   //设置端点0的发送缓冲区地址

  Clear_Status_Out(ENDP0);   //清除端点0的状态

  SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);//设置端点0的接收的计数

  SetEPRxValid(ENDP0);   //使能接收状态


  /* Initialize Endpoint 1 */

     SetEPType(ENDP1, EP_INTERRUPT); //设置端点1为中断控制端点

     SetEPRxAddr(ENDP1, ENDP1_RXADDR); //设置端点1的接收缓冲地址

     SetEPRxCount(ENDP1, REPORT_COUNT); //设置端点1的接收计数

     SetEPRxStatus(ENDP1, EP_RX_VALID); //设置端点1接收有效

     //SetEPTxStatus(ENDP1, EP_TX_DIS);


  /* Initialize Endpoint 2 */

     SetEPType(ENDP2, EP_INTERRUPT); //设置端点2为中断控制端点

     SetEPTxAddr(ENDP2, ENDP2_TXADDR); //设置端点2的接收缓冲地址

     SetEPTxCount(ENDP2, REPORT_COUNT); //设置端点2的接收计数

    // SetEPTxStatus(ENDP2, EP_TX_DIS);

     SetEPTxStatus(ENDP2, EP_TX_NAK); //设置端点2为接收不响应


     bDeviceState = ATTACHED; //设置设备状态为 ATTACHED状态

  /* Set this device to response on default address */

  SetDeviceAddress(0); //设置设备为默认地址

#endif /* STM32F10X_CL */


  bDeviceState = ATTACHED;

}

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

* Function Name  : CustomHID_SetConfiguration.

* Description    : 更新设备配置状态

* Input          : None.

* Output         : None.

* Return         : None.

推荐阅读

史海拾趣

DS-IMP公司的发展小趣事

DS-IMP公司的前身是一家美国公司,在转移到中国大陆后,面临了技术转移和本土化的挑战。公司迅速组建了一支由资深工程师和技术专家组成的团队,他们与美国的原团队紧密合作,成功地将核心技术从美国转移到宁波的工厂。在本土化过程中,公司不仅保留了原技术的精髓,还根据中国大陆的市场需求和资源特点,对部分技术和产品进行了优化和升级。这一过程不仅提升了公司的技术实力,也为公司在中国市场的快速发展奠定了坚实基础。

Etco Inc公司的发展小趣事

自1947年成立以来,Etco Inc公司一直致力于电子连接技术的研发与创新。在20世纪70年代,公司成功研发出一款新型的高性能连接器,该产品凭借其卓越的性能和可靠性,迅速在汽车电子行业中占据了一席之地。这一技术突破不仅为Etco带来了可观的市场份额,还奠定了其在电子连接器领域的技术领先地位。

Hirect公司的发展小趣事
晶闸管在控制信号的作用下,实现快速的开通和关断,从而实现对输出电压的脉冲调制。
Autonics公司的发展小趣事

Autonics始终将产品质量放在首位,建立了严格的质量管理体系。公司引进了先进的生产设备和检测设备,确保产品的生产和质量控制达到国际先进水平。同时,Autonics还积极申请并获得了多项国际产品质量认证,如ISO9001、UL、CE等,进一步提升了产品的竞争力和市场认可度。

弘凯光电(BRIGHTEK)公司的发展小趣事

2021年,弘凯光电在江苏南通投资建设了集成智慧光源项目,总投资额高达10亿元。这一项目的建成,不仅大幅提升了公司的产能和效率,更为汽车照明、智能家居、3C电子等LED高端应用领域提供了高品质的产品。项目的成功投产,标志着弘凯光电在光电半导体领域的技术实力和市场地位得到了进一步提升。

Cal-Chip Electronics公司的发展小趣事

为了进一步提升竞争力,Cal-Chip Electronics公司在XXXX年开始实施产业链整合战略。公司通过与上游原材料供应商和下游终端制造商建立紧密的合作关系,实现了产业链的协同发展和资源共享。这一战略不仅降低了公司的运营成本,也提高了产品的质量和生产效率。同时,公司还积极参与行业标准的制定和推广,推动了整个行业的健康发展。

问答坊 | AI 解惑

没有旋钮的收音机

普通的机械调频收音机有两个必须的旋钮:频率调谐旋钮和音量控制旋钮,但是图片里这只看起来憨厚可爱的收音机缺让人找不到这两个旋钮在哪里,该怎么操作呢 答案:通过左右摇摆这个像长鼻子一样伸出来的天线,就可以调整频率,而头顶上的扬声器的外 ...…

查看全部问答>

环保当道 混合动力车辆引爆半导体新商机

据市场研究机构Strategy Analytics的预测,在混合动力车辆应用领域的半导体组件营业额将由今年的5亿美元,在2015年迅速成长到13亿美元;其中以电源组件为大宗,还有模拟微控制器与传感器。       Strategy Analytics表示,包 ...…

查看全部问答>

warning 15

warning 15:multiple call  to segment: 这个警告是什么意思啊,如何修改啊…

查看全部问答>

请有经验的大师推荐一款带adc的单片机

有没有谁推荐一款能达到这样要求的带adc的芯片?采样速度在1kHz大一点就可以,精度不要太高都行。并且做过相关的实践,保证能实行。非常感谢!现在非常急呀,导师天天催着要结果。…

查看全部问答>

菜鸟求助!!!

学单片机有一段时间了,学的是汇编,现在陷入了困境中了,就是我搞不清楚各个端口的准确地址,还有各个端口地址到底是多少位! 比如说 mov p0,#10H 我给P0口赋值10,到底是给P0.0-P0.7的那个端口赋值! 请大大们给我解释一下啊,我现在是一头雾 ...…

查看全部问答>

如何才能做一个合格的采购师?

 从事采购工作有一段时间了,感觉真的是豪无头绪呀。请各位朋友们帮我找找方法如何去找到头绪好吗?…

查看全部问答>

UCosii在STM32上的移植,这个错误是什么原因呢

Build target \'Stm32-ucosII-demo\'linking....\\Output\\Stm32-ucosII-demo.axf: Error: L6218E: Undefined symbol BSPInit (referred from app.o)..\\Output\\Stm32-ucosII-demo.axf: Not enough information to list image symbols..\\Output ...…

查看全部问答>

寻求AT91SAM7S64的例程

各位大虾,小弟想用AT91SAM7S64的USB,自己对USB协议也基本上了解,但没有ATMEL  USB的例程,所以写起代码来,还是觉得无从着手,不知道该怎么具体的实现,ATMEL官网也没找到(应该都有例程的啊),所以麻烦各位大虾能给小弟指点迷津,感 ...…

查看全部问答>