【VC++开源代码栏目提醒】:网学会员--在 VC++开源代码编辑为广大网友搜集整理了:基于STM32的USB程序开发笔记 - 电子设计绩等信息,祝愿广大网友取得需要的信息,参考学习。
基于STM32 的USB程序开发笔记 以前一直就有打玩 USB 的想法,最近时间充足于是决心打玩 STM32 的 USB,购买的是万利的 STM3210B-LK1 板,琢磨 USB 已有半个多月,在固 件、上位机驱动以及应用程序的访问这三方面终于有所突破,这期间通过网络上授寻了许多相关资料,主要来自 ST 提供的 USB 固件,以及圈圈 computer00提供的一些关于 USB 驱动开发的资料,通过这段时间的学习,了解到学习 USB 对于未接触过的朋友来说确实存在许多的知识壁垒,本 着
开源精神,在此对 STM32 的 USB 固件程序的编写、DriverStudio WindowsXP DDK
VC6 驱动开发以及应用
程序做了一些介绍,为更好理解,请仔细
学习 STM32 USB 的参考手册以及 USB 协议,如果对
VC6 下开发还不是太熟悉或者说不曾学过,那么如果想理解有些
问题,就必须学习
VC6 了。
本套笔记是基于我编写的程序进行说明的,请配合该程序进行学习。
第一篇:需要准备的一些资料 1:STM32 的参考手册,这对于设备底层 USB 的硬件配置以及事件驱动机制的了解尤为重要,你需要了解各个寄存器的功能以及如何操作,比如 CNTR、ISTR、EPnR、DADDR 等等,如果你想学习 USB,这个手册是必须的。
2:USB2.0 协议,这个资料同样必不可少,如果因为英语阅读能力而苦苦寻找中文版的 USB2.0 协议,建议不要这么做,现在
网络中的所谓的中文版的 USB2.0 协议不 是官方撰写的,大多数是一些热心朋友自己翻译的,却不是很全面,如果你在为寻找这类的资料而无所获时,建议认真塌实的看看官方英文版的 USB2.0 协议, 官方协议阐述的十分详细,650 多页,一字一句的了解全部协议不太可行,可针对性的重点理解,比如对第 9 章 USB Device Framework 的详细理解对于你的 USB Device 固件开发不可缺少(这里就是 STM32)。
3:ST提供的USB固件库,这个类库较为散乱,但不可不参考以下是链接包含固件、驱动以及应用程序,固件部分有些功能是不被支持的,如SR_SetDescriptor、 SR_SynchFrame等等,在此说明不支持非故意如此,而是还没去更仔细深入编写完善,目前这些不被支持的部分目前不被使用到。
下载链接:http://blog.ednchina.com/lbxxx如果你使用的是万利的 STM3210B-LK1 开发板,则可以烧写 hex 文件后直接进行测试。
以下一组图片说明的 XP 下驱动的安装过程以及测试软件打开后的情形,仅参考。
测试
软件:控制万利 STM3210B-LK1 开发板的 4 个 LED,并定时读取 Joystick 状态 第 2 篇:STM32 USB 固件函数的驱动原理首先需要了解一个概念:USB 设备(DEVICE)从来只是被动触发,USB 主机(HOST)掌握主动权,发送什么数据,什么时候发送,是给设备数据还是从设备请求数据,都是由 USB 主机完成的,USB 设备只是配合主机完成设备的枚举、数据方向和大小。
根据数据特性再决定该不该回复该如何回复、该不该接收该如何接收这些动作。
了解这些,再仔细查看 STM32 的参考手册 USB 部分以及 STM32 的中断向量表,从中可以找到两个中断:/ Function Name : USB_HP_CAN_TX_IRQHandler Description : This function handles USB High Priority or CAN TX interrupts requests. Input : None Output : None Return : None/void USB_HP_CAN_TX_IRQHandlervoid USB_HPI/ Function Name : USB_LP_CAN_RX0_IRQHandler Description : This function handles USB Low Priority or CAN RX0 interrupts requests. Input : None Output : None Return : None/void USB_LP_CAN_RX0_IRQHandlervoid USB_LPI即 USB 的高、低优先权中断处理函数,这也是整个 STM32 USB 的事件驱动源,USB_HPI与 USB_LPI既而转向 usb_core.c.h进行相关处理。
中断传输interrupt、控 制传输control、大流量传输bulk由 USB_LPI响应,大流量传输bulk同样可能响应USB_HPI,同步传输 isochronous只响应 USB_HPI。
这样响应 USB 的所有请求只需要关注 usb_core.c 文件中的 USB_LPI与 USB_HPI函数。
由于本人也是对 USB 刚刚有所了解,因而在本例笔记中 USB_HPI函数未做任何处理,在此
开源希望大 家能完善与纠正错误并能共享喜悦。
以下是 USB_LPI函数:// // Function Name : USB_LPI.// Description : Low Priority Interrupts service routine.// Input :// Output :// Return :// void USB_LPIvoid unsigned short wValISTR GetISTRifCNTR_MASK ISTR_RESET // Reset ifwValISTR ISTR_RESET vwInterruptMask SetISTRCLR_RESET INT_ISTR_RESET endififCNTR_MASK ISTR_DOVR // DMA Over/Underrun ifwValISTR ISTR_DOVR vwInterruptMask SetISTRCLR_DOVR INT_ISTR_DOVR endififCNTR_MASK ISTR_ERR // Error ifwValISTR ISTR_ERR vwInterruptMask SetISTRCLR_ERR INT_ISTR_ERROR endififCNTR_MASK ISTR_WKUP // Wakeup ifwValISTR ISTR_WKUP vwInterruptMask SetISTRCLR_WKUP INT_ISTR_WAKEUP endififCNTR_MASK ISTR_SUSP // Suspend ifwValISTR ISTR_SUSP vwInterruptMask INT_ISTR_SUSPEND SetISTRCLR_SUSP // must be done after setting of CNTR_FSUSP endififCNTR_MASK ISTR_SOF // Start Of Frame ifwValISTR ISTR_SOF vwInterruptMask SetISTRCLR_SOF INT_ISTR_SOF endififCNTR_MASK ISTR_ESOF // Expected Start Of Frame ifwValISTR ISTR_ESOF vwInterruptMask SetISTRCLR_ESOF INT_ISTR_ESOF endififCNTR_MASK ISTR_CTR // Correct Transfer ifwValISTR ISTR_CTR vwInterruptMask INT_ISTR_CTR endif// // Function Name : USB_HPI.// Description : High Priority Interrupts service routine.// Input :// Output :// Return :// void USB_HPIvoid可 以看出,在 USB_LPI函数中,根据 STM32 USB 的中断状态寄存器(ISTR)的标志位的状态以及定义的 USB 控制寄存器中断事件屏蔽码,响应各自的中断事件,比如 INT_ISTR_RESET响应 USB 的复位中断,一般可在此函数内进行 USB 的寄存器的初始化;INT_ISTR_CTR响应一次正确的数据 传输中断,故名思意,在完成一次正确的数据传输操作后,就会响应此函数。
具体含义请仔细查阅 STM32 参考手册。
第 3 篇:STM32 USB 固件函数的一些介绍STM32 USB 中断事件为以下几种,详细情况可以查看 usb_core.c/.h:void ISTR_CTRvoidvoid ISTR_SOFvoidvoid ISTR_ESOFvoidvoid ISTR_DOVRvoidvoid ISTR_ERRORvoidvoid ISTR_RESETvoidvoid ISTR_WAKEUPvoidvoid ISTR_SUSPENDvoid这些处理函数使能由定义 CNTR_MASK 决定:// CNTR mask controldefine CNTR_MASK CNTR_CTRM CNTR_WKUPM CNTR_SUSPM CNTR_ERRM CNTR_SOFM CNTR_ESOFM CNTR_RESETM CNTR_DOVRM 其中着重说明的是 ISTR_RESET和 ISTR_CTR函数,ISTR_RESET主要处理 USB 复位后进行一些初始化任务,ISTR_CTR则是处理数据正确传输后控制,比如说响应主机。
// // Function Name : INT_ISTR_RESET// Description : ISTR Reset Interrupt service routines.// Input :// Output :// Return :// void INT_ISTR_RESETvoid // Set the buffer table address SetBTABLEBASEADDR_BTABLE // Set the endpoint type: ENDP0 SetEPR_TypeENDP0 EP_CONTROL Clr_StateOutENDP0 // Set the endpoint data buffer address: ENDP0 RX SetBuffDescTable_RXCountENDP0 ENDP0_PACKETSIZE SetBuffDescTable_RXAddrENDP0 ENDP0_RXADDR // Set the endpoint data buffer address: ENDP0 TX SetBuffDescTable_TXCountENDP0 0 SetBuffDescTable_TXAddrENDP0 ENDP0_TXADDR // Initialize the RX/TX status: ENDP0 SetEPR_RXStatusENDP0 EP_RX_VALID SetEPR_TXStatusENDP0 EP_TX_NAK // Set the endpoint address: ENDP0 SetEPR_AddressENDP0 ENDP0 // ---------------------------------------------------------------------// TODO: Add you code here// ---------------------------------------------------------------------// Set the endpoint type: ENDP1SetEPR_TypeENDP1 EP_INTERRUPTClr_StateOutENDP1// Set the endpoint data buffer address: ENDP1 RXSetBuffDescTable_RXCountENDP1 ENDP1_PACKETSIZESetBuffDescTable_RXAddrENDP1 ENDP1_RXADDR// Set the endpoint data buffer address: ENDP1 TXSetBuffDescTable_TXCountENDP1 0SetBuffDescTable_TXAddrENDP1 ENDP1_TXADDR// Initialize the RX/TX status: ENDP1SetEPR_RXStatusENDP1 EP_RX_VALIDSetEPR_TXStatusENDP1 EP_TX_DIS// Set the endpoint address: ENDP1SetEPR_AddressENDP1 ENDP1SetEPR_TypeENDP2 EP_INTERRUPTClr_StateOutENDP2// Set the endpoint data buffer address: ENDP2 RXSetBuffDescTable_RXCountENDP2 ENDP2_PACKETSIZESetBuffDescTable_RXAddrENDP2 ENDP2_RXADDR// Set the endpoint data buffer address: ENDP2 TXSetBuffDescTable_TXCountENDP2 0SetBuffDescTable_TXAddrENDP2 ENDP2_TXADDR// Initialize the RX/TX status: ENDP2SetEPR_RXStatusENDP2 EP_RX_DISSetEPR_TXStatusENDP2 EP_TX_VALID// Set the endpoint address: ENDP2SetEPR_AddressENDP2 ENDP2// ---------------------------------------------------------------------// End of you code// ---------------------------------------------------------------------SetDADDR0x0080 vsDeviceInfo.bDeviceAddressvsDeviceInfo.eDeviceState DS_DEFAULTvsDeviceInfo.bCurrentFeature 0x00vsDeviceInfo.bCurrentConfiguration 0x00vsDeviceInfo.bCurrentInterface 0x00 vsDeviceInfo.bCurrentAlternateSetting 0x00 vsDeviceInfo.uStatusInfo.w 0x0000在这个 ISTR_CTR函数中,定义了 EP0、1、2 的传输方式以及各自的缓冲描述符,其中 EP0 是默认端口,负责完成 USB 设备的枚举,一般情况是不需要更改的。
其他端点配置则需根据实际应用而决定,如何设置请仔细理解 STM32 的参考手册。
值 得说明的是 STM32 的端点 RX/TX 缓冲描述表是定义在 PMA 中的,他是基于分组缓冲区描述报表寄存器BTABLE而定位的,各端点RX/TX 缓冲 描述表说明是数据存储地址以及大小,这个概念需要了解,ST 提供的固件很含糊,为此,我在 usb_regs.h 文件中进行了重新定义,如下:// USB_IP Packet Memory Area base addressdefine PMAAddr 0x40006000L// Buffer Table address registerdefine BTABLE volatile unsigned RegBase 0x50// // Packet memory area: Total 512Bytes// define BASEADDR_BTABLE 0x0000// // PMAAddr BASEADDR_BTABLE 0x00000000 : EP0_TX_ADDR// PMAAddr BASEADDR_BTABLE 0x00000002 : EP0_TX_COUNT// PMAAddr BASEADDR_BTABLE 0x00000004 : EP0_RX_ADDR// PMAAddr BASEADDR_BTABLE 0x00000006 : EP0_RX_COUNT//// PMAAddr BASEADDR_BTABLE 0x00000008 : EP1_TX_ADDR// PMAAddr BASEADDR_BTABLE 0x0000000A : EP1_TX_COUNT// PMAAddr BASEADDR_BTABLE 0x0000000C : EP1_RX_ADDR// PMAAddr BASEADDR_BTABLE 0x0000000E : EP1_RX_COUNT//// PMAAddr BASEADDR_BTABLE 0x00000010 : EP2_TX_ADDR// PMAAddr BASEADDR_BTABLE 0x00000012 : EP2_TX_COUNT// PMAAddr BASEADDR_BTABLE 0x00000014 : EP2_RX_ADDR// PMAAddr BASEADDR_BTABLE 0x00000016 : EP2_RX_COUNT//// PMAAddr BASEADDR_BTABLE 0x00000018 : EP3_TX_ADDR// PMAAddr BASEADDR_BTABLE 0x0000001A : EP3_TX_COUNT// PMAAddr BASEADDR_BTABLE 0x0000001C : EP3_RX_ADDR// PMAAddr BASEADDR_BTABLE 0x0000001E : EP3_RX_COUNT//// PMAAddr BASEADDR_BTABLE 0x00000020 : EP4_TX_ADDR// PMAAddr BASEADDR_BTABLE 0x00000022 : EP4_TX_COUNT// PMAAddr BASEADDR_BTABLE 0x00000024 : EP4_RX_ADDR// PMAAddr BASEADDR_BTABLE 0x00000026 : EP4_RX_COUNT//// PMAAddr BASEADDR_BTABLE 0x00000028 : EP5_TX_ADDR// PMAAddr BASEADDR_BTABLE 0x0000002A : EP5_TX_COUNT// PMAAddr BASEADDR_BTABLE 0x0000002C : EP5_RX_ADDR// PMAAddr BASEADDR_BTABLE 0x0000002E : EP5_RX_COUNT//// PMAAddr BASEADDR_BTABLE 0x00000030 : EP6_TX_ADDR// PMAAddr BASEADDR_BTABLE 0x00000032 : EP6_TX_COUNT// PMAAddr BASEADDR_BTABLE 0x00000034 : EP6_RX_ADDR// PMAAddr BASEADDR_BTABLE 0x00000036 : EP6_RX_COUNT//// PMAAddr BASEADDR_BTABLE 0x00000038 : EP7_TX_ADDR// PMAAddr BASEADDR_BTABLE 0x0000003A : EP7_TX_COUNT// PMAAddr BASEADDR_BTABLE 0x0000003C : EP7_RX_ADDR// PMAAddr BASEADDR_BTABLE 0x0000003E : EP7_RX_COUNT// //// PMAAddr BASEADDR_BTABLE 0x00000040 - 0x000001FF : assigned to data buffer//// define BASEADDR_DATA BASEADDR_BTABLE 0x00000040// ENP0define ENDP0_PACKETSIZE 0x40define ENDP0_RXADDR BASEADDR_DATAdefine ENDP0_TXADDR ENDP0_RXADDR ENDP0_PACKETSIZE// ENP1define ENDP1_PACKETSIZE 0x40define ENDP1_RXADDR ENDP0_TXADDR ENDP0_PACKETSIZEdefine ENDP1_TXADDR ENDP1_RXADDR ENDP1_PACKETSIZE// ENP2define ENDP2_PACKETSIZE 0x40define ENDP2_RXADDR ENDP1_TXADDR ENDP1_PACKETSIZEdefine ENDP2_TXADDR ENDP2_RXADDR ENDP2_PACKETSIZE// ENP3define ENDP3_PACKETSIZE 0x40define ENDP3_RXADDR ENDP2_TXADDR ENDP2_PACKETSIZEdefine ENDP3_TXADDR ENDP3_RXADDR ENDP3_PACKETSIZE// ENP4define ENDP4_PACKETSIZE 0x40define ENDP4_RXADDR ENDP3_TXADDR ENDP3_PACKETSIZEdefine ENDP4_TXADDR ENDP4_RXADDR ENDP4_PACKETSIZE// ENP5define ENDP5_PACKETSIZE 0x40define ENDP5_RXADDR ENDP4_TXADDR ENDP4_PACKETSIZEdefine ENDP5_TXADDR ENDP5_RXADDR ENDP5_PACKETSIZE// ENP6define ENDP6_PACKETSIZE 0x40define ENDP6_RXADDR ENDP5_TXADDR ENDP5_PACKETSIZEdefine ENDP6_TXADDR ENDP6_RXADDR ENDP6_PACKETSIZE// ENP7define ENDP7_PACKETSIZE 0x40define ENDP7_RXADDR ENDP6_TXADDR ENDP6_PACKETSIZEdefine ENDP7_TXADDR ENDP7_RXADDR ENDP7_PACKETSIZE这样,一般只要在 PMA 的大小区域内(512Bytes),修改端点 EPnR 的数据包大小就可以了,当然,实际情况可以根据需要进行更改。
// // Function Name : INT_ISTR_CTR// Description : ISTR Correct Transfer Interrupt service routine.// Input :// Output :// Return :// void INT_ISTR_CTRvoid unsigned short wEPIndex unsigned short wValISTR unsigned short wValENDP while wValISTRGetISTR ISTR_CTR 0 // Get the index number of the endpoints wEPIndex wValISTR ISTR_EP_ID ifwEPIndex 0 // Set endpoint0 RX/TX status: NAK Negative-Acknowlegment SetEPR_RXStatusENDP0 EP_RX_NAK SetEPR_TXStatusENDP0 EP_TX_NAK // Transfer directionifwValISTR ISTR_DIR 0 // DIR0: IN // DIR0 implies that EP_CTR_TX always 1 ClrEPR_CTR_TXENDP0 CTR_IN0 returnelse // DIR1: SETUP or OUT // DIR1 implies that CTR_TX or CTR_RX always 1 wValENDP GetEPRENDP0 ifwValENDP EP_CTR_TX 0 ClrEPR_CTR_TXENDP0 CTR_IN0 return else ifwValENDP EP_SETUP 0 ClrEPR_CTR_RXENDP0 CTR_SETUP0 return