,将STM32的USB枚举为HID设备。
2,STM32使用3个端点,端点0用于枚举用,端点1和2用于数据的发送和接收。
3,端点长度为64,也就是单次最多可以传输64个字节数据。
4,STM32获取上位机下发的数据并将该数据通过USB原样返回,同时将数据打印输出。
5,上位机程序通过调用windows的API实现对HID设备的读写控制。
主要是分析官方的Custom_HID 例程,强烈建议大家结合USB2.0协议去分析源代码。特别不错,分析完之后就可以修改移植了。另外,有个叫源享科技的出了一套80集的关于STM32的整套视频,对USB等高级外设讲的非常透彻,结合原子的开发板学习,效果也很好的。那视频在源享科技官网上挺贵的,哈哈,最后我在淘宝上发现那些新开的店最便宜的才10块钱。老板是个挺厉害的研究生,在学USB的时候帮了我不少。。废话不说了,关于修改官方例程的步骤::附件USB程序
一、usb_desc.c文件
根据你程序使用的通信方式修改。usb_desc.h文件中定义要根据usb_desc.c文件中的数组的大小;ConfigDescriptor[SIZ_CONFIG_DESC]下添加需要处理的端点;根据需要添加或删除报告描述符(主要用于HID)和CDC接口描述符(主要用于实现USB转串口)等。具体方法可以下载个“电脑圈圈”使用D12编写的例子。
二、Usb_conf.h文件:
1、修改需要处理那些中断
CNTR_CTRM
处理数据正确传输后控制,比如说响应主机
CNTR_DOVRM
/* DMA OVeR/underrun Mask */
CNTR_ERRM
/* ERRor Mask */
CNTR_WKUPM 0
/* WaKe UP Mask */
CNTR_SUSPM
/* SUSPend Mask */
CNTR_RESETM
主要处理USB复位后进行一些初始化任务
CNTR_SOFM
/* Start Of Frame Mask */
CNTR_ESOFM
/* Expected Start Of Frame Mask */
如:
usb_conf.h中的#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM )是决定USB_CNTR寄存器中的那个USB相关中断启动还是屏蔽。
2、根据需要增加端点缓存地址,要根据缓存区的地址修改,防止数据重叠
如下为根据每个缓冲区的大小为64字节修改:
#define ENDP1_TXADDR
(0xC0)
#define ENDP1_RXADDR
(0xD0)
#define ENDP2_TXADDR
(0x100)
#define ENDP2_RXADDR
(0x140)
#define ENDP3_TXADDR
(0x180)
#define ENDP3_RXADDR
(0x1C0)
3、修改/* CTR service routines */下的EPX_IN_Callback和EPX_OUT_Callback。注释掉需要处理的函数。NOP_Process表示不处理。
三usb_prop.c文件
1、修改void XX_Reset(void)(如:void Joystick_Reset(void))
一般/* Initialize Endpoint 0 */的不用修改,如下为举例说明端点1的初始化,其他端口原理一样。
SetEPType(ENDP1, EP_INTERRUPT);//设置端点1类型
/*EP_BULK
批量端点
EP_CONTROL 控制端点
EP_ISOCHRNOUS 同步端点
EP_INTERRUPT 中断端点*/
SetEPTxAddr(ENDP1, ENDP1_TXADDR); //设置端点1缓冲区基地址
SetEPTxCount(ENDP1, 64);// 配置Tx 缓冲计数器
SetEPRxStatus(ENDP1, EP_RX_DIS);// //设置端点接收关闭
SetEPTxStatus(ENDP1, EP_TX_NAK);// //设置端点1发送不应答
/*
#define EP_RX_DIS
(0x0000) // EndPoint RX DISabled 端点接收关闭
#define EP_RX_STALL
(0x1000) // EndPoint RX STALLed 端点接收延迟
#define EP_RX_NAK
(0x2000) // EndPoint RX NAKed 端点接收不应答
#define EP_RX_VALID
(0x3000) // EndPoint RX VALID端点接收有效
#define EP_TX_DIS
(0x0000) //EndPoint TX DISabled
#define EP_TX_STALL
(0x0010) // EndPoint TX STALLed
#define EP_TX_NAK
(0x0020) // EndPoint TX NAKed
#define EP_TX_VALID
(0x0030) // EndPoint TX VALID */
2、删除不相干的描述符等。
如自定义的USB设备就不需要以下结构体初始化:
ONE_DESCRIPTOR Joystick_Report_Descriptor
ONE_DESCRIPTOR Mouse_Hid_Descriptor
3、修改RESULT XX_Data_Setup(u8 RequestNo)的数据类请求处理。
如Custom_HID例程修改为“自定义USB设备”例程时可以将以下代码删除
if ((RequestNo == GET_DESCRIPTOR)
(Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
(pInformation-USBwIndex0 == 0))
{
if (pInformation-USBwValue1 == REPORT_DESCRIPTOR)
{
CopyRoutine = Joystick_GetReportDescriptor;
}
else if (pInformation-USBwValue1 == HID_DESCRIPTOR_TYPE)
{
CopyRoutine = Joystick_GetHIDDescriptor;
4、删除不相干的获得描述符返回函数
如自定义的USB设备就不需要以下函数:
Joystick_GetReportDescriptor
Joystick_GetHIDDescriptor
四、usb_endp.c文件
1、增加之前定义的中断数据处理函数
如:
void EP1_OUT_Callback(void)
{
这些写接收代码
五、数据发送和接收,举例说明
1、数据接收
u8 DataLen;
DataLen = GetEPRxCount(ENDP1);
PMAToUserBufferCopy(TX1_buffer, ENDP1_RXADDR, DataLen);
SetEPRxValid(ENDP1);
USART1_Send(DataLen);
count_out = 1;
2、数据发送
UserToPMABufferCopy(InBuffer, GetEPTxAddr(ENDP1), 64);
SetEPTxCount(ENDP1, 64);
SetEPTxValid(ENDP1);
如果你发送数据较为频繁,每次发送前应使用GetEPTxStatus(ENDP1)检测上次发送是否完成。如果端点状态处于EP_TX_VALID,说明发送未结束,如果端点状态处于EP_TX_NAK,说明发送结束。
1.USB Resume信号
USB设备进入挂起状态之后,将由Resume信号进行唤醒。Resume信号可以由USB主机发起,也可以由USB设备本身触发,但是只有USB主机可以结束Resume信号。
(1)主机在挂起设备后可通过翻转数据线上的极性并保持20ms来唤醒设备,并以低速EOP信号结尾。
(2)如果设备支持远程唤醒,设备可向主机发起远程唤醒请求,前提是设备已进入idle状态至少5ms,设备会驱动总线进入K状态,如下图,K状态必须维持1ms-15ms之内,此信号会在1ms内被主机接管,主机会继续驱动唤醒信号直到20ms,并以低速EOP信号结尾。
2.USB远程唤醒的方式
当主机控制器进入挂起后,所有设备是没办法向主机提交数据的,那主机是怎样知道设备的唤醒请求呢?答案是通过电信号。如下图(usb_20.pdf Page-333),设备需要生成一个1ms-15ms的K状态电信号(这里例子为10ms),hub会在1ms内捕获到该信号(此时设备其实就可以停止驱动K状态了),hub会进行和设备相同的操作把此信号传递给主机控制器,主机控制器对唤醒操作进行接管,主机会继续驱动唤醒信号直到20ms,并以低速EOP信号结尾,完成对设备的唤醒操作。如果是一个鼠标设备的话,休眠的系统有时会被恢复,其实这里大家可以看做是设备给主机系统发送一个IO中断信号,主机系统检测到后可以实现一系列的后续操作。
3.J状态和K状态
J状态 LS(低速) 差分0
FS(全速) 差分1
K状态 LS(低速) 差分1
FS(全速) 差分0
4.STM32 USB设备远程唤醒机制详解
首先我们以我自己设计的STM32 USB鼠标例子来分析。
1.USB外设需支持远程唤醒操作
USB外设必须支持远程唤醒功能,当然STM32F103 USB外设符合USB2.0全速设备的技术规范,所以支持远程唤醒的功能。
2.USB设备描述符设置远程唤醒
USB设备配置描述符设备属性中必须Bit5必须为1(remote wake-up)。
STM32F103鼠标设备配置描述符源代码如下,从0数第7个字节0xE0(1110000b),标识设备是自供电且具有远程唤醒功能。
3.STM32 USB设备远程唤醒代码剖析
实现的功能就是STM32按下一个按键后,STM32 USB设备发送一次远程
本文标签:stm32usb控制电路设计