如何使用STM32的USB库支持控制端点0
- 格式:pdf
- 大小:90.79 KB
- 文档页数:4
基于STM32F103芯片的USB接口的研究与实现一、本文概述随着科技的飞速发展,USB接口作为一种便捷、高效的数据传输方式,在电子设备中得到了广泛应用。
STM32F103芯片作为STMicroelectronics公司推出的一款基于ARM Cortex-M3内核的32位微控制器,具有高性能、低功耗、易于编程等优点,被广泛应用于各种嵌入式系统中。
本文将围绕STM32F103芯片的USB接口展开研究,详细探讨其原理、设计与实现方法。
本文首先介绍了STM32F103芯片的基本特性和USB接口的基本原理,包括USB协议栈、数据传输方式等。
接着,对STM32F103芯片的USB 接口硬件设计进行了详细描述,包括硬件电路的选择、接口电路设计、电源管理等。
在软件设计方面,本文详细介绍了USB驱动程序的开发过程,包括驱动程序的架构、主要功能实现以及关键技术的处理等。
为了实现STM32F103芯片与USB设备之间的数据传输,本文还设计了基于USB HID类设备的通信协议。
该协议利用USB HID类设备的通用性,实现了STM32F103芯片与USB设备之间的无缝连接和数据传输。
本文还通过实验验证了USB接口设计与实现的正确性,并分析了在实际应用中的性能表现。
本文总结了STM32F103芯片USB接口的研究与实现过程,指出了其中存在的不足之处,并对未来的研究方向进行了展望。
通过本文的研究,旨在为嵌入式系统开发人员提供一种基于STM32F103芯片的USB接口设计与实现方案,推动嵌入式系统中USB接口技术的进一步发展。
二、STM32F103芯片USB接口基础知识STM32F103芯片是STMicroelectronics公司生产的一款基于ARM Cortex-M3核心的微控制器,它集成了丰富的外设接口,其中包括USB 接口。
对于STM32F103来说,其USB接口主要基于USB 0标准,提供了高速的数据传输能力。
STM32F103的USB接口主要由以下几个部分构成:USB外设控制器、USB收发器以及USB的电源管理。
STM32 的USB缓冲区1.分组缓冲区的首地址为0x4000 60002.两个地址:usb模块;APB1地址。
APB1地址 = 2*USB模块地址。
3.分组缓冲区的首地址由USB_BTABLE来确定:USB_BTABLE的低3位=04.缓冲区寄存器地址分布:缓冲区寄存器分为节点控制寄存器和数据存储寄存器.节点控制寄存器依次包含:发送缓冲区地址寄存器(USB_BTABLE+n*10)Æ发送数据字节数(USB_BTABLE+n*10+4)Æ接收缓冲区地址寄存器(USB_BTABLE+n*10+8)Æ接收数据字节数(USB_BTABLE+n*10+C)缓冲区地址寄存器都是半字对齐的,故其最低位bit0=0;接收数据字节数与发送数据字节数不同:接收的数据字节数寄存器:bit15 bit14~bit10 bit9~bit0BL_SIZE:存储区块大小 NUM_BLOCK:块数目(简称N) COUNTn_RX:实际收到的字节数=1,块=32字节,可分配32*1~512字节(31*32>512) =0,块=2字节,可分配2*1~31*2字节 BL_SIZE=0:可用块数目为N*2注:(N!=0)BL_SIZE=1:可用块数目为(N+1)*32注:N可以=0,小于16次10位有USB模块硬件自己设置.(只读)发送的数据字节寄存器:bit9~bit0记录收到下一个IN分组时需要发送的字节数双缓冲端点和IN端点都有两个接收/发送字节数寄存器:DATA1(bit25~bit16)和DATA0(bit9~bit0)USB缓冲区的操作1.系统重启后,使能时钟和寄存器.2.控制端点0被使能:控制USB_ADDR.EF(使能寄存器操作)和EP0R的相关寄存器来实现.端点0总是配置成单缓冲模式.3.端点初始化:。
stm32f042usb编程-回复stm32f042是一款由意法半导体(STMicroelectronics)公司推出的32位ARM Cortex-M0微控制器,专门用于USB通信应用的开发。
本文将从基础知识开始,一步一步回答有关stm32f042usb编程的问题,旨在帮助读者了解如何使用stm32f042进行USB通信的开发。
首先,我们需要了解一些基础知识。
USB(Universal Serial Bus)是一种用于连接计算机与外部设备的通用接口标准,它能够提供高速、可靠的数据传输。
stm32f042具有内置的USB硬件,可支持USB设备和USB主机功能。
对于USB设备通信开发,stm32f042可以作为USB设备,与主机进行通信。
一、开发环境搭建1. 在PC上安装Keil MDK开发工具。
Keil MDK是一种基于ARM Cortex-M处理器的嵌入式软件开发环境,提供了丰富的开发工具和库函数。
2. 在Keil MDK中创建一个新的工程,并选择stm32f042芯片型号。
3. 配置工程的编译选项和链接选项,使之与stm32f042芯片匹配。
4. 编写应用程序代码,实现USB设备通信功能。
二、USB设备初始化1. 在应用程序的主函数中,调用USB设备初始化函数。
该函数会初始化USB硬件并配置相关寄存器。
2. 配置USB设备的功能描述符。
功能描述符是一组数据结构,用于描述设备所支持的功能和特性。
3. 配置USB设备的端点。
端点是USB通信的基本单位,用于发送和接收数据。
4. 启动USB设备。
使能USB硬件,并设置USB设备状态为“已连接”。
三、USB设备事件处理1. 在应用程序中,通过中断或轮询方式检测USB设备事件的发生。
2. 根据事件类型,执行相应的处理函数。
例如,当检测到USB设备启动事件时,执行设备初始化函数。
3. 在处理函数中,根据具体的应用需求,执行相应的操作。
例如,当检测到USB设备接收到数据时,执行数据处理函数。
STM32USB设备描述符、配置描述符、端点描述符含义查了⼀整天的资料,⾃⼰把不懂的全部试了⼀遍⼀下是程序以及注释/* USB设备描述符*/const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] ={0x12, /*bLength 描述符的长度*/USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType 描述符的类型(设备描述符为0x01)*/0x00, /*bcdUSB USB协议的版本*/0x02,0x00, /*bDeviceClass 类代码*/0x00, /*bDeviceSubClass ⼦类代码*/0x00, /*bDeviceProtocol 设备所使⽤的协议*/0x40, /*bMaxPacketSize 端点0的最⼤包长*//*idVendor ⼚商ID*/LOBYTE(USB_VID),HIBYTE(USB_VID),/*idProduct 设备ID*/LOBYTE(USB_PID),HIBYTE(USB_PID),0x00, /*bcdDevice rel 设备版本号*/0x02,1, /*描述⽣产⼚家的字符串描述符的索引*/2, /*描述产品的字符串描述符的索引*/3, /*产品序列号的字符串描述符的索引*/0x01/*bNumConfigurations 可能的配置数*/}; /* CustomHID_DeviceDescriptor *//* USB配置描述符 *//* All Descriptor s (Configuration, Interface, Endpoint, Class, Vendor */const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] ={//以下为配置描述符0x09, /* bLength: 端点描述符长度*/USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: 描述符类型(配置描述符为0x02) */LOBYTE(CUSTOMHID_SIZ_CONFIG_DESC),/* wTotalLength: 配置描述符集合总长度 */HIBYTE(CUSTOMHID_SIZ_CONFIG_DESC),0x01, /* bNumInterfaces: 该配置所⽀持的接⼝数*/0x01, /* bConfigurationValue: 该配置的值*/0x00, /* iConfiguration: 描述配置的字符串描述符的索引*/0xA0, /* bmAttributes:该设备的属性(总线供电,⽀持远程唤醒)bit 4 ... 0: 保留(必须为0)bit 5: 1表⽰⽀持远程唤醒bit 6: 1表⽰设备是⾃供电 0表⽰是总线供电bit 7: 保留(必须为1) */0xC8, /* MaxPower 设备所需要的电流(单位为2mA)400 mA*///以下为接⼝描述符0x09, /* bLength: 接⼝描述符长度*/USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType: 描述符类型(接⼝描述符为0x04)*/0x00, /* bInterfaceNumber: 该接⼝编号(从0开始) */0x00, /* bAlternateSetting: 该接⼝的备⽤编号 */0x02, /* bNumEndpoints 该接⼝所使⽤的端点数*/0x03, /* bInterfaceClass: 该接⼝所使⽤的类*/0x00, /* bInterfaceSubClass : 该接⼝所使⽤的⼦类 */0x00, /* nInterfaceProtocol : 该接⼝所使⽤的协议 0 =⽆,1 =键盘,2 =⿏标*/0, /* iInterface: 描述该接⼝的字符串描述符的索引 *///以下为HID描述符0x09, /* bLength: HID描述符长度 */HID_DESCRIPTOR_TYPE, /* bDescriptorType: 描述符类型(接⼝描述符为0x21) */0x10, /* bcdHID: HID 协议版本号 */0x01,0x00, /* bCountryCode: 国家代码 (美式键盘代码为0x21)*/0x01, /* bNumDescriptors:下级描述符的数量*/0x22, /* bDescriptorType 下级描述符的类型*/LOBYTE(CUSTOMHID_SIZ_REPORT_DESC),/* wItemLength: 下级描述符的长度*/HIBYTE(CUSTOMHID_SIZ_REPORT_DESC),//以下为端点描述符/******************** Descriptor of Custom HID endpoints ******************/0x07, /* bLength:端点描述符长度 */USB_ENDPOINT_DESCRIPTOR_TYPE, /* 描述符类型(端点描述符为0x05)*/0x81, /* bEndpointAddress:端点地址bit 3 ... 0:端点号bit 6 ... 4:保留(设置为0)bit 7:0(OUT),1(IN)*/0x03, /* bmAttributes: 端点属性bit 1 ... 0:表⽰该端点的传输类型0 控制传输1 等时传输2 批量传输3 中断传输bit 7 ... 2:如果该端点是⾮等时传输则bit 7 ~ 2 保留(设置为0)如果该端点是等时传输bit 3 ... 2:表⽰同步类型0 ⽆同步1 异步2 适配3 同步bit 5 ... 4:表⽰⽤途0 数据端点1 反馈端点2 暗含反馈的数据端点3 保留bit 7 ... 6:保留*/0x40, /* wMaxPacketSize: 该端点⽀持的最⼤包长度 */0x00,0x0A, /* bInterval:端⼝的查询时间*///以下为输出端点1描述符0x07, /*bLength:端点描述符⼤⼩ */USB_ENDPOINT_DESCRIPTOR_TYPE, /* 端点描述符类型*/0x01, /* bEndpointAddress:端点地址bit 3 ... 0:端点号bit 6 ... 4:保留bit 7:0(OUT),1(IN)*/0x03, /* bmAttributes: 中断端点 */0x40, /* wMaxPacketSize: 最多64个字节 */0x00,0x0A, /* bInterval: 轮询间隔(20毫秒)*/};。
STM32 USB设计单片机程序篇首先,我们来看看usb的工作过程。
当usb设备接入到主机时,主机开始枚举usb设备,并向usb设备发出指令要求获取usb 设备的相关描述信息,其中包括设备描述(device descriptor)、配置描述(configuration descriptor)、接口描述(interface descriptor)、端点描述(endpoint descriptor)等。
这些信息是通过端点0(endpoint 0)传送到主机的。
获取各种描述信息后,操作系统会为其配置相应的资源。
这样主机就可以与设备之间进行通信了。
usb通讯有四种通讯方式控制(control)、中断(interrupt)、批量(bulk)和同步(synchronous)。
usb通讯是通过管道(pipe)实现的。
管道是一个抽象的概念,指的是主机与设备之间通讯的虚拟链路。
不如说一个usb通讯主机A和设备B,其中有bulk in(批量输入)、bulk out(批量输出)、control out(控制输出)三种通讯方式,那么A与B之间的通讯管道就有三个。
(这里明确一个概念,在usb通信中数据流向都是相对设备来说的,in表示设备向主机传送数据,out表示表示主机箱设备传输数据)。
在设备一端,每个管道对应一个端点,端点配置相关的寄存器和缓冲区。
在通讯之前需对端点进行相关设置。
在通信中,只需向缓冲写或读数据,并置位相关比特位即可。
下面具体从usb的中断输入输出来讲述基于keil C mdk开发环境的stm32的USB接口单片机程序设计。
值得一提的是,st或相关公司给我们提供许多封装函数和相关例子,我们可以根据其中的例子并进行修改即可实现我们自己需要的usb通讯程序。
b描述符配置从上面的讲述可以看出,usb描述符是usb通讯的前提。
主机必须先了解设备后才能与其进行通讯。
在st提供的例子中,描述符都在usb_des.c文件进行定义,下面就其中的Joystick例子说明usb描述负的配置。
基于STM32F103的USB2.0代码一、简介STM32F103是意法半导体推出的一款基于ARM Cortex-M3内核的微控制器,具有丰富的外设功能和较高的性能。
USB(Universal Serial Bus)是一种通用串行总线,广泛应用于计算机和其他电子设备之间的数据传输和连接。
基于STM32F103的USB2.0代码即指针对STM32F103微控制器开发的支持USB2.0标准的代码。
二、USB2.0USB2.0是Universal Serial Bus的第二代标准,具有高速传输和广泛兼容的特点。
USB2.0可以实现最高480Mbps的数据传输速度,是USB1.1标准的40倍。
在电脑外设、数字相机、移动设备等领域得到了广泛的应用。
三、基于STM32F103的USB2.0代码开发1. 硬件支持在使用STM32F103微控制器开发USB2.0代码时,首先需要确保硬件的支持。
STM32F103系列微控制器内部集成了USB OTG(On-The-Go)功能,支持USB2.0协议。
通过配置GPIO端口和时钟等硬件资源,可以实现与USB外设的连接。
2. USB Library意法半导体提供了相应的USB库,用于快速开发基于STM32F103的USB2.0代码。
该库包括了USB设备协议栈(Device stack)和USB主机协议栈(Host stack),可以根据实际应用选择相应的协议栈进行开发。
USB库还提供了丰富的例程和示例代码,便于开发者进行参考和调试。
3. USB协议栈在开发基于STM32F103的USB2.0代码时,需要了解USB协议栈的原理和实现。
USB协议栈主要包括物理层(Physical Layer)、传输层(Transport Layer)、设备层(Device Layer)和应用层(Application Layer)等,开发者需要对每一层的功能和接口进行深入理解,以便进行代码的开发和调试。
如何使用STM32的USB库支持控制端点0发布者:STM32 发布时间:2009-11-25 17:59首先我们先回顾一下控制端点的传输方式:控制端点的传输有三个阶段,SETUP阶段、数据阶段和状态阶段;数据阶段又分为数据入(DATA IN)和数据出(DATA OUT),控制端点传输可以没有数据阶段;状态阶段有状态入(STATUS IN)和状态出(STATUS OUT)。
总结起来,控制端点有如下三种可能的传输过程(以下括号中的0或1表示DATA0或DATA1传输):一、 SETUP DATA_IN(0) DATA_IN(1) DATA_IN(0) ...... STATUS_OUT(1)二、 SETUP DATA_OUT(0) DATA_OUT(1) DATA_OUT(0) ...... STATUS_IN(1)三、 SETUP STATUS_IN(1)这里做一个约定,把上述过程一定义为“数据入过程”,过程二定义为“数据出过程”,过程三定义为“无数据过程”。
所有的USB控制端点的数据传输都可以而且只用这三种传输过程表示。
HID的SET_REPORT是数据出过程,HID的GET_REPORT是数据入过程,USB的GET DEVICE DESCRIPTOR是数据入过程,USB的SET CONFIGURATION是无数据过程,等等。
接下来,我们看看STM32的USB库是如何处理控制端点0的传输。
根据USB协议,每个SETUP包都由8个字节构成,用户程序可以通过结构体Device_Info(类型DEVICE_INFO)访问SETUP包的数据,因为在整个的USB处理中都要用到结构体Device_Info的内容,库中定义了一个全局的指针pInformation指向这个结构体,用户可以通过这个指针访问结构体的内容。
对应SETUP包的8个字节,用户可以用下述方式访问:pInformation->USBbmRequestType (字节类型)pInformation->USBbRequest (字节类型)pInformation->USBwValue (双字节类型)pInformation->USBwIndex (双字节类型)pInformation->USBwLength (双字节类型)使用pInformation->USBwValue0访问wValue的低字节,pInformation->USBwValue1访问wValue的高字节。
使用pInformation->USBwIndex0访问USBwIndex的低字节,pInformation->USBwIndex1访问USBwIndex的高字节。
使用pInformation->USBwLength0访问USBwLength的低字节,pInformation->USBwLength1访问USBwLength的高字节。
通过分析SETUP包的8个字节,可以判断出一个SETUP的传输过程是属于数据入过程、数据出过程还是无数据过程。
STM32的USB库中处理了所有的USB协议文本中定义的标准SETUP 命令,对于USB协议文本中未定义的命令,USB库按照数据入过程、数据出过程或无数据过程通过回调函数交给用户程序处理。
全局变量Device_Property(DEVICE_PROP类型)封装了所有的回调函数,DEVICE_PROP定义如下:typedef struct _DEVICE_PROP{void (*Init)(void); // 设备初始化回调函数void (*Reset)(void); // USB复位回调函数void (*Process_Status_IN)(void); // STATUS_IN阶段处理回调函数void (*Process_Status_OUT)(void); // STATUS_OUT阶段处理回调函数RESULT (*Class_Data_Setup)(u8 RequestNo); // 数据入/出过程处理回调函数RESULT (*Class_NoData_Setup)(u8 RequestNo); // 无数据过程处理回调函数RESULT (*Class_Get_Interface_Setting)(u8 Interface, u8 AlternateSetting); // GET_INTERFACE 回调函数u8* (*GetDeviceDescriptor)(u16 Length); // GET_DEVICE_DESCRIPTION回调函数u8* (*GetConfigDescriptor)(u16 Length); // GET_CONFIGURATION_DESCRIPTION回调函数u8* (*GetStringDescriptor)(u16 Length); // GET_STRING_DESCRIPTION回调函数u8 MaxPacketSize; // 最大包长度} DEVICE_PROP;结合SETUP的三种传输过程,用户通过实现不同的回调函数即可完成对各种USB类命令的处理,下面以HID的SET REPORT为例说明。
在介绍具体实现之前,先介绍一下另一个回调函数CopyRoutine的概念,这个函数的原型是:u8 *CopyRoutine(u16 length); // 返回一个缓冲区指针USB库通过这个函数获得用户的数据缓冲区地址,从而可以在数据出过程中把收到的数据拷贝到用户缓冲区,或在数据入过程中把用户缓冲区的数据拷贝到USB发送缓冲区。
每个数据出过程可能有若干次DATA_OUT传输,USB库每完成一次这样的传输都会调用一次回调函数CopyRoutine,参数length是本次传输所收到的数据字节数目,CopyRoutine必须返回一个缓冲区指针,这个缓冲区必须能够容纳length字节的数据,CopyRoutine返回到USB库之后,USB库将把收到的数据拷贝到用户指定的缓冲区。
同样每个数据入过程也可能有若干次DATA_IN传输,每次需要向主机传输数据时,USB库都会调用一次回调函数CopyRoutine,参数length是本次传输所要发送的数据字节数目,CopyRoutine必须返回一个缓冲区指针,这个缓冲区中必须包含要求的数据字节,USB库将把用户缓冲区的数据拷贝到USB缓冲区并择机发送出去。
当以length=0调用CopyRoutine时,CopyRoutine需要返回用户缓冲区的长度,因为CopyRoutine的返回类型是一个指针,所以需要通过类型的强制转换返回缓冲区长度。
这个功能是为了处理用户缓冲区的长度与主机SETUP数据请求长度不符的情况,而不至于造成用户缓冲区的溢出。
介绍完上述若干概念和回调函数,再看SET_REPORT的实现就很容易了。
SET_REPORT是一个数据出过程,因此需要实现一个Class_Data_Setup回调函数,示例如下:RESULT HID_Data_Setup(u8 RequestNo){u8 *(*CopyRoutine)(u16 length);CopyRoutine = NULL;if (pInformation->USBbmRequestType == CLASS_REQUEST|INTERFACE_RECIPIENT&& RequestNo == SET_REPORT)CopyRoutine = My_Data_Request;if (CopyRoutine == NULL)return USB_UNSUPPORT;pInformation->Ctrl_Info.CopyData = CopyRoutine;pInformation->Ctrl_b_wOffset = 0;pInformation->Usb_wLength = (*CopyRoutine)(0);return USB_SUCCESS;} // End of HID_Data_Setup()u8 My_Buffer[10];u8 *My_Data_Request(u16 length){if (length == 0)return (u8*)10; // 假定你的REPORT长度和Buffer长度为10return My_Buffer;}上面介绍的CopyRoutine用于把多次传输的数据包合并到一个完整的缓冲区中,因此只有到STATUS阶段才能够知道一次SETUPProcess_Status_IN中处理从SET_REPORT接收到的数据。
因为所有的回调函数都是USB中断处理的一部分,所以更好的办法是在 Process_Status_IN中设置一个标记,然后在用户主程序中判断这个标记并做处理。
上述示意代码是以My_Buffer长度为10字节为例,而USB库的默认包长度为16字节,因此My_Data_Request并没有多包的处理。
关于多包的缓冲区处理的示意代码可以是这样的:u8 *My_Data_Request(u16 length){if (length == 0)return (u8*)100; // 假定你的REPORT长度和Buffer长度为100return &My_Buffer[pInformation->Ctrl_b_wOffset];}这里有一个库中使用的变量pInformation->Ctrl_b_wOffset,这个变量会在传输每个数据包时候由库中的程序按数据包长度增加,如最大包长为16字节时,第一次调用My_Data_Request时Usb_wOffset=0,第二次调用 My_Data_Request时Usb_wOffset=16,第三次调用My_Data_Request时Usb_wOffset=32,依此类推。
这样就可以使用Usb_wOffset 作为My_Buffer的下标从My_Data_Request返回相应的缓冲区地址。
前面已经说明,参数length是用于检测缓冲区长度是否足够,如果你有足够长的缓冲区,可以不必检测,上述示例中使用了一个固定的缓冲区,所以不必使用参数length检测缓冲区长度。
注意,STM32的USB库设计成以回调函数处理用户命令请求,包含类命令请求,是为了能够清晰地区分库程序和用户程序,使这两者不会混在一起,这样的好处是非常明显的,当USB 库需要更新升级时,只需替换掉相应的程序模块,而不必修改用户已经完成的程序。
以上的介绍都可以在STM32 USB库的说明手册中找到。