侵权投诉
技术:
GPU/CPU 传感器 基础元器件 网络通信 显示 交互技术 电源管理 材料 操作系统 APP 云技术 大数据 人工智能 制造 其它
应用:
可穿戴设备 智能家居 VR/AR 机器人 无人机 手机数码 汽车 平衡车/自行车 医疗健康 运动设备 美颜塑身 早教/玩具 安防监控 智能照明 其它
订阅
纠错
加入自媒体

USB开发,这个错误你犯了吗?

如果板子的晶振是8M,那么参数需要做如下配置:

(OSC IN = 8M)

PREDIV1SRC  =  0b0, HSE oscillator clock selected as PREDIV1 clock entry

PREDIV1 = 0b0, PREDIV1 input clock not divided

PLLSRC = 0b1, Clock from PREDIV1 selected as PLL input clock

PLLMUL = 0b0111, PLL input clock x 9

(PLLCLK = 72M)

SW = 0b10, PLL selected as system clock

PLLVCO = 2*PLLCLK  = 144M

USBPRE = 0, PLL clock is divided by 1.5 (or PLLVCO/3)

USB Clock =  = PLLCLK/1.5 = 72M/1.5 = 48M

例程中的对应代码修改:

最后修改使用的串口引脚:

stm32f1xx_hal_msp.c

//AFIOCOMx_REMAP(0);    // Remap USART2 to PTD5/6

usbd_cdc_interface.h

Definition for USARTx Pins

//#define USARTx_TX_PIN       GPIO_PIN_5

//#define USARTx_TX_GPIO_PORT   GPIOD

//#define USARTx_RX_PIN       GPIO_PIN_6

//#define USARTx_RX_GPIO_PORT   GPIOD

#define USARTx_TX_PIN        GPIO_PIN_2

#define USARTx_TX_GPIO_PORT    GPIOA

#define USARTx_RX_PIN        GPIO_PIN_3

#define USARTx_RX_GPIO_PORT    GPIOA

终于可以编译运行了,用USB线把板子连到PC的USB口,记得把板子的PTA2和PTA3引脚短接起来。在设备管理器我们看到多出来一个串口,看它的属性会看到它的VID,PID跟我们程序中设置的一致。

用串口助手打开此串口,发送字符串,会看到返回同样的字符串。

下面我们来看一下具体的工作过程。

3.USB枚举(Enumeration)

当我们给设备上电,程序控制芯片内集成的上拉电阻连接至USBDP时,USB主机(PC端)会检测到这一变化并向设备供电。此时设备处于Powered状态。

主机等待100ms设备稳定后复位并使能此端口,此时设备可以从Vbus获取不超过 100mA 的电流,其默认地址是0,处于Default状态。

主机通过0地址向该设备发送Get_Descriptor标准请求,获取设备的描述符。主机再次复位该PORT,并发送标准请求Set_Address给设备分配一个地址,之后的通信都是用此地址,设备进入Address状态。

主机通过新地址向设备再次发送Get_Descriptor标准请求,获取设备描述符。发送Get_Configuration请求,获取配置描述符。一个设备可以有多个配置,主机选择合适配置,通过 Set_Configuration请求对设备而进行配置,设备进入Configured状态。

USB的枚举过程是标准的,所以库里也有对应的标准处理代码。我们可以不用关心。好了,现在可以开始数据的双向传输了。

4.数据传输

我们已经了解所有USB传输都是由USB主机(Host)发起的,作为USB设备只能是被动的等待。当Host下发请求时会在设备中产生各种中断,设备完成各种中断的处理就行了。其中需要特别关注的有两个:

OEPINT(Output Endpoint Int),表明主机下发了数据。

IEPINT(Output Endpoint Int)。表明主机请求设备上传数据。

那么用户在代码里如何收发USB数据的呢?

我们在usbd_cdc_interface.c里关注下面这些就够了:

uint8_t UserRxBuffer[APP_RX_DATA_SIZE]; //USB下发数据缓冲区

uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; //需要发给USB上位机的数据缓冲区

下面这个函数是用户用来处理接收缓冲区数据的,在初始化时需要传递给USB驱动,然后驱动收到USB下发的数据后会回调此函数。在例程中此函数把接收数据转发给了USART2。当然你也可以什么都不做。

static int8_t CDC_Itf_Receive(uint8_t * Buf, uint32_t * Len);

那么如果有数据需要发给上位机呢?我们可以用下面这个函数:

USBD_CDC_TransmitPacket(&USBD_Device);

注意此数据是先放入IN端点,然后等待IEPINT中断发生时才被取走发送。

5.一个重要又容易被忽视的问题

至此好像万事大吉了。

等等,如果产品这样发出去,你可能给公司惹麻烦了!

还有一个很重要的问题我们千万不要忽视,就是VID和PID,既厂商识别符(Vendor ID)和产品识别符(Product ID)。我们例程中使用的是VID 0x0483, PID 0x5740。这个VID是专门分配给ST的,虽然我们用这个号程序也能运行,但是不符合规范的。我们的可以在 usb.org/developers 网站查到当前为所有USB厂商分配的VID。如果我们要开发USB设备,还要向USB组织申请自己的VID,之后还要做微软徽标认证,就可以畅行无阻了。

参考资料:

UM1734 STM32Cube USB device library

USB Specification 2.0

Universal Serial Bus Class Definitions for Communications Devices 1.2

STM32F105xx Datasheet

STM32F105xx RM

<上一页  1  2  
声明: 本文由入驻维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。

发表评论

0条评论,0人参与

请输入评论内容...

请输入评论/评论长度6~500个字

您提交的评论过于频繁,请输入验证码继续

暂无评论

暂无评论

    智能硬件 猎头职位 更多
    文章纠错
    x
    *文字标题:
    *纠错内容:
    联系邮箱:
    *验 证 码:

    粤公网安备 44030502002758号