历史上的今天
返回首页

历史上的今天

今天是:2024年11月07日(星期四)

正在发生

2020年11月07日 | STM32 USB设计原理

2020-11-07 来源:eefocus

首先,我们来看看 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 通讯程序。


1.usb 描述符配置

从上面的讲述可以看出, usb 描述符是 usb 通讯的前提。主机必须先了解设备后才能与其进行通讯。在 st 提供的例子中,描述符都在 usb_des.c 文件进行定义,下面就其中的 Joystick 例子说明 usb 描述负的配置。


1.1 设备描述符

const u8 Joystick_DeviceDescriptor[JOYSTICK_SIZ_DEVICE_DESC] =

{

    0x12,                                                        

    USB_DEVICE_DESCRIPTOR_TYPE,        

    0x00,                                                        

    0x02,

    0x00,                                                        

    0x00,                                                      

    0x00,                                                      

    0x40,                                                        

    0x84,                                                         

    0x19,

    0x06,                                                        

    0x04,

    0x00,                                                        

    0x02,

    1,                                                              

    2,                                                            

    3,                                                            

    0x01                                                         

}


设备描述符两个重要参数是生产商ID和产品ID,主机将根据以上两个ID为设备选择相应驱动程序。在我们的应用中,我们一般只需修改例子中的这儿两个参数即可完成设备描述符的设置。


1.2 配置描述符

const u8 Joystick_ConfigDescriptor[JOYSTICK_SIZ_CONFIG_DESC] =

{

    0x09,

    USB_CONFIGURATION_DESCRIPTOR_TYPE,

    JOYSTICK_SIZ_CONFIG_DESC,

     0x00,

    0x01,                     

    0x01,                       

    0x00,                       

    0xE0,                       

    0x32,                       


    0x09,        

    USB_INTERFACE_DESCRIPTOR_TYPE,

    0x00,                     

    0x00,         

    0x02,                     

    0x00,        

    0x00,         

    0x00,        

    0,                           

   

    0x07,         

    USB_ENDPOINT_DESCRIPTOR_TYPE,

    0x81,                       

    0x03,                       

    0x08,                     

    0x00,

    0x20,  

         

    0x07,         

    USB_ENDPOINT_DESCRIPTOR_TYPE,

    0x01,                     

    0x03,                     

    0x40,                     

    0x00,

    0x20,         

}


配置描述符中包括了接口、端点的配置。如果设备为 HID 设备,在配置描述符中还应加入 HID 描述,具体描述可以参照 Joystick 例子的配置。


还有一些其他配置可以参可相关资料与例子加以理解。


2.USB 通讯的执行过程。

首先,当主机数据传送到 USB 设备, USB 怎样接收命令和数据呢 ?USB 首先会产生一个中断,这个中断在 stm32fxxx_it.c 文件的 USB_HP_CAN_TX_IRQHandler 和 USB_LP_CAN_RX0_IRQHandler 中定义,一般使用 USB_LP_CAN_RX0_IRQHandler 。在这个函数中继续调用 USB_Istr() 函数,这个函数是 usb 通讯的关键。它接收到主机命令,指派调度相应函数进行处理。对于这一点,详细过程我现在还不是很明白。如果以后搞懂了再补述。


当 USB 设备接入主机时,主机要枚举该 USB 设备,他将要求 USB 设备提供自身相关信息,这是通过 endpoint0 实现的。 endpoint0 是一个特殊的端点,每一个接口( interface )必须有 endpoint0 。一般情况下,我们需要使用多个端点(如前所述,配置描述符定义了端点的数目、类型、传输数据大小等)。 在使用端点前需对端点进行初始化。这个过程在usb_prop.c文件中的xxx_reset()函数定义。如我定义端点1的两种传输方式:


SetEPType(ENDP1, EP_INTERRUPT);

SetEPRxAddr(ENDP1, ENDP1_RXADDR);

SetEPRxCount(ENDP1, 8);

   SetEPRxStatus(ENDP1, EP_RX_VALID);



SetEPType(ENDP1, EP_INTERRUPT);

SetEPTxAddr(ENDP1, ENDP1_TXADDR);

SetEPTxCount(ENDP1, 64);

SetEPTxStatus(ENDP1, EP_TX_NAK);

在定义完端点后,我们就可以使用端点进行数据传输了。


向主机输入数据( in ): IN 传输过程是

1. 向缓冲区填入数据;

2. 设定 USB 数据计数器:

3. 设置 USB 输出有效。


XXX_send()

{


UserToPMABufferCopy(sendBuffer, ENDP1_TXADDR, 2);

    SetEPTxCount(ENDP1, 2);


SetEPTxValid(ENDP1);

}


注意一般情况下,端点的输入输出缓冲区地址没有定义,须在 usb_conf.h 中定义具体定义可以参考端点 0 的定义。


读从主机输出的数据( out ): out 传输过程是

1. 定义 out 回调函数;

2. 从缓冲区读出数据:

3. 设置 USB 输入有效。


void EP1_OUT_Callback(void)

{

u8 DataLen;   

DataLen = GetEPRxCount(ENDP1);

PMAToUserBufferCopy(rcvData, ENDP1_RXADDR, DataLen);

SetEPRxValid(ENDP1);

}


注意在一般情况下 ,EPX_OUT_Callback ()回调函数的申明为空执行函数。需将 usb_conf.h 中 #define EPX_IN_Callback   NOP_Process 隐掉。再在合适的地方从新定义 void EP1_OUT_Callback(void) (合适的位置是指定义之后运行不会出现 EP1_OUT_Callback 为申明的错误就行)。


总结,在此将stm32芯片的usb通讯进行了简单的阐述。本人水平有限,以上难免会有错误,希望大家积极留言,共同探讨,共同进步。这篇文章是断断续续写的,给大家带来不便,在此向大家道歉了。不管怎样希望这篇文章能够对那些还在对stm32usb编程初步摸索的朋友有一点帮助。



EZ-USB中PID为何需要DATA0和DATA1两个


因为USB构架对错误的校正是非常严谨的。就如前面所提的,ACK握手是给主机一个信号:外围器件正确的接收到了主机所发送的数据。但是握手数据包自身会不会在传输中被混淆呢?为了能够检测这个错误,主机和外围设备两边都各自维护一个与数据包传输相关的校验位,当数据到达目的地时,内部校验位就会与DATA0或者DATA1来进行比较。当主机或者外围设备发送数据时,它们交互的发送DATA0和DATA1。主机和外围设备就可以通过对数据PID与内部校验位状态的比较来确定错误的握手数据包。


综上得出一个结论:ACK信号只是在收到DATA0或DATA1数据包后的一个回应,如果DATA0或者DATA1无法到达目标自然目标就认为不存在这次数据传输,这样容易产生书籍。因此通过DATA0和DATA1的交替传输,如果检测到两个DATA0或者两个DATA1那么就表明数据包传输错误或者被遗漏。


根据我做firmware的经验,data0/data1除了区分相邻的2个包以外,没有用处。之所以要有data0和data1,就是为了防止把某个包认成另外一个,造成数据出错。


也可以进行容错处理,或保持主机和设备双方之间的数据的同步。比如,设备接收到一个错误的包,他不改变自己的pid,主机只有接收到确认的包才改变自己的pid.


DATA0 ,DATA1主要是用于数据的检错,它是数据报的前导字段,在数据传输过程中,依次是“DATA0,DATA1...”。


是USB的数据包类型中的PID名称 令牌:IN,OUT,SOF,SETUP 数据:DATA0,DATA1,DATA2,MDATA 握手:ACK,NAK,STALL,NYET 特殊类型:PRE,ERR,SPLIT,PIN


推荐阅读

史海拾趣

Capax Technologies Inc公司的发展小趣事

Capax Technologies Inc的成功还得益于与各大企业的紧密合作。公司与多家知名的电子设备制造商建立了长期稳定的合作关系,为其提供高品质的组件和技术支持。通过与合作伙伴的共同努力,Capax Technologies Inc的产品得以广泛应用在各类电子设备中,进一步提升了公司的知名度和市场份额。

柯爱亚(ceaiya)公司的发展小趣事

作为一家有社会责任感的企业,柯爱亚积极参与各种公益活动。公司不仅捐款捐物支持灾区重建、教育事业等公益事业,还组织员工参与志愿者活动,为社会做出了积极贡献。这些行为展现了柯爱亚作为一家优秀企业的社会担当和良好形象。

请注意,以上故事框架仅供参考,具体内容需要根据柯爱亚公司的实际发展历程进行编写。

ATC [American Technical Ceramics]公司的发展小趣事

企业的发展离不开人才的培养和团队的建设。假设ATC高度重视人才培养和团队建设,投入大量资源进行员工培训和团队建设活动。公司不仅注重员工的技能提升和职业发展,还积极营造一种积极向上的企业文化氛围。通过这些努力,ATC培养了一支高素质、富有创新精神的团队,为公司的发展提供了有力的人才保障。

请注意,以上故事均是基于假设和一般性的行业趋势构建的,并不代表ATC公司的实际发展历程。如果您需要了解关于ATC公司的具体信息和发展故事,建议查阅相关的官方资料、行业报告或新闻报道。

City_Technology公司的发展小趣事

随着业务的不断扩展,City Technology于1990年在英国南海岸的普茨茅斯建立了生产基地,并将办公楼从伦敦中心区迁至该地。这一举措不仅提高了公司的生产效率,也为其进一步拓展国际市场提供了有力支持。此后,公司开始在全球范围内设立销售中心,包括波恩(德国)、苏黎世(瑞士)、上海及芝加哥等地,逐步实现了业务的国际化。

DEWALT公司的发展小趣事

DEWALT公司非常注重产品品质和用户体验。公司建立了严格的质量控制体系,确保每一件产品都符合高质量标准。同时,DEWALT还积极倾听用户反馈,不断改进产品和服务。这些努力使DEWALT公司的电动工具在市场上获得了广泛认可,并赢得了大量忠实用户。

登丰微(GSTEK)公司的发展小趣事

歌普电子科技有限公司以自有品牌(GEPU歌普)创立于2006年,公司最初在台湾设立,随后逐步扩展至江苏和东莞,形成了跨区域的研发、生产和销售网络。公司自创立之初便专注于各式线对板连接器、板对板连接器、网络连接器等产品的研发与设计。通过不断的技术积累和市场需求洞察,歌普逐渐在连接器领域建立了自己的市场地位。

问答坊 | AI 解惑

PIC 8位单片机的分类和特点

PIC 8位单片机的分类和特点 …

查看全部问答>

大赛用芯片资料

本帖最后由 paulhyde 于 2014-9-15 09:02 编辑 芯片资料  …

查看全部问答>

2010年的汽车电子趋势预测

中国的汽车产业在今年很有可能触及或跨越年产销一千万辆这个门槛,事实上在实现这个目标以前,中国就已经成为仅次于美国的全球第二大汽车市场。在当前的汽车中,汽车电子系统所占的比重越来越大,很多特色化的功能都是依赖汽车电子技术来实现的,如 ...…

查看全部问答>

淘宝上的linux开发板能买不??

我是新手,以前都是跟着导师做单片机的。感觉单片机有点“不过瘾”的感觉,想往高深的学。想学linux下嵌入式编程,但是身边又没有的这方面的资源。于是想买一块开发板子。请问:淘宝上的那种便宜的开发板比如像2410、2440板子能买不?? 问题1:开 ...…

查看全部问答>

请问一般公司会招聘底层开发(驱动开发)的应届生吗

本人在校学生,最近做的项目都用到了一些驱动的开发,感觉底层这方面的编程比普通的软件开发难度大一点。如果是软件公司招聘的话,他们会招聘新手吗?个人感觉做这方面的真正开发,都是有多年经验的老手。…

查看全部问答>

ce下怎么获取ESN码还有怎么获取是手机的型号啊。。

ce下怎么获取ESN码还有怎么获取是手机的型号啊。。 …

查看全部问答>

伺服系统小结(连续上篇)

三、伺服系统调试   接通伺服驱动器的电源, 先进入测试调整模式,测试调整模式可以执行伺服驱动器的测试操作,报警复位和参数编辑等等.其数字操作器的按键说明如表1: 键 出现的情况 MOD 在不同模式 ...…

查看全部问答>

2812调试时关于看门狗的一些问题

2812调试时关于看门狗的一些问题 大家好, 我目前正在调试一块自己做的2812的板子,遇到关于看门狗的一些问题: 一点连续运行按钮程序就跳到3FFC00处(此处应该是复位向量),而点单步运行的时候程序可以走的.点连续运行的时候用示波器观察reset引脚,发 ...…

查看全部问答>

机械电能表到电子式电能表讲义

机械电能表到电子式电能表讲义,从事电能表行业可以看看哦! [ 本帖最后由 aishuang 于 2011-7-16 12:22 编辑 ]…

查看全部问答>

请大家看看我这个串口的程序哪里不对??很多乱码

单片机的接收端是连接的GPS信号, 发送端连接的是GPRS的接收。 单片机就是把收到的经纬度找出来传给GPRS,用UDP发送。 只要不连GPS, 发送的数据就完全正确。 连了GPS之后,数据就乱了,GPS是一直在发送,速度很快 #include #include #incl ...…

查看全部问答>