STM32 - 3
时钟和USB接口
时钟
一些缩写
- 外部高速时钟:HSE
- 内部高速时钟:HSI
- 时钟和复位控制:RCC(Reset and Clock Control)
STM32的时钟系统简介
这个图是官方手册的时钟树的简化版,为了便于理解,可以从中间的SYSCLK,把整个时钟树分为两部分:左边为时钟源,右边为片上外设。
系统时钟来源选择
可以看到SYSCLK旁边的那个梯形,就是一个选择器,由他来选择STM32究竟用哪个时钟源。HSE、HSI就不再多说,中间的那个PLL叫锁相环,用来做倍频的,就是把HSI或HSE做一定的倍频之后再作为整个片上外设的时钟输入。
片上外设时钟
SYSCLK右边,会首先过一个AHB总线进行分频,把输入的时钟频率分成1/n,变成了HCLK。然后HCLK一分为二, 去供给片上外设。其中APB1的最大频率比APB2低一些,即APB2的时钟的最高频率搞一些,功耗也高一些,适合高频的片上外设。
- APB1和APB2是两条总线,都挂载在AHB总线上
- 驱动Cortex-M3内核的时钟是HCLK
STM32时钟编程接口
API
首先了解两个API:
|
|
时钟配置
首先,我们需要去配置时钟来源。从上面的API可以看到,配置时钟源需要一个RCC_OscInitTypeDef
,其定义可以去看源码,现在我们就以外部时钟源+9倍频锁相环为例,看看怎么配置:
|
|
设置完时钟源之后,就可以设置后续的时钟了,代码如下:
|
|
最后一个参数的FLASH_LATENCY
配置,实际上和你设置的时钟SYSCLK有关系,具体多少频率的时钟对应多少FLASH_LATENCY
需要去库里面的代码里看注释。
到这里,时钟就配置完了。更多的时钟配置可以去看HAL库的源代码手册。
USB
USB介绍
首先需要介绍下usb的基本概念和参数,这对于在stm32上使用usb设备有很大的帮助。
USB默认是个4pin设备,其中中间的D+和D-分别会接一个15K的下拉电阻:
所以,默认D+和D-默认都是低电平。然而,在USB插头上面,D+会接一个1.5K的上拉电阻,这样的话一旦插入USB设备,D+就会被拉到高电平,产生一个中断表名设备已连接。
USB分为主机和设备,所有的通信都是由主机(比如PC)发起的,输入和输出也都是针对主机而言。
USB的传输类型
一共4种:
- 控制:一般是用于初次连接的初始化,比如分配地址、获取USB设备信息等
- 中断:主机会定时询问是否有数据,这就是鼠标、键盘等设备的通信模式
- 批量:大文件传输
- 同步:数据同步,比如摄像头
USB供电
USB可以给设备供电,这是通过VBUS来供电的。USB2.0给低功耗设备供电电流最多可以100ma。对于高功耗设备,最高不超过500ma。
USB配置描述符
上面说的这些配置,比如是否低功耗设备等,都是在最初连接的时候,设备通过USB配置描述符告诉主机的。下面是一个例子,可以参考下。具体所有的描述符建议去USB的官方查看官方文档:
USB HID
USB支持很多种设备类型,我们主要会用到HID,即Human Interface Device。
USB挂起模式
当USB主机连续3ms没有检测到USB设备有信号,就自动进入USB挂起模式。因此,为了避免进入挂起模式,设备需要周期性地发送Keep Alive或者SOF信号。
HID键盘的键值
对于USB HID设备来说,其键盘的数据包包含8个字节。基本上可以分为3部分:
- Byte0:功能键,如L/R-Ctrl、Shift、Alt、GUI等
- Byte1:保留
- Byte2-7:普通按键
对于普通按键来说,HID设备已经规定好了各个按键的键值,比如右箭头的键值为79(十六进制0x4F)。如果要向主机发送一个右箭头按键,那么在Byte2写个0x4F就行了。
STM32的USB配置
默认情况下,STM32CubeMX生成的USB HID设备是鼠标,需要修改配置描述符来修改为键盘的键值。首先看一下STM32CubeMX配置USB的界面:
左下角可以看到F411是USB_OTG_FS,意思是带OTF的全速USB设备。中间可以看到相关的配置项,对于键盘设备一般选Device Only即可。下面是休眠和供电的选项,选不选都可以。
然后,在middleware下选择USB_DEVICE,就可以看到作为USB设备的相关配置:
中间的Class For FS IP就选择HID设备,下面的Device Descriptor设备描述符,就可以配置这个USB设备连接到电脑上之后的一些信息,比如厂家、设备名等等。然后生成代码即可。
默认情况下,CubeMX生成的HID设备是鼠标。在生成的代码中,找到usbd_hid.c
文件,找到这段代码:
可以看到有一个nInterfaceProtocol
,在默认情况下值为0x02,即mouse。对于键盘我们把它改成0x01即可。此外,在下面还有一个HID_MOUSE_REPORT_DESC_SIZE
常量,指的是鼠标的回报描述符的大小,我们也需要把它改为键盘的大小:
需要注意的是,这个DESC_SIZE有两处,都需要改为键盘。
改完上面三个地方之后,我们的代码就可以作为键盘的USBHID设备连接到电脑上了。
数据传输
最后的最后,在代码中只需要调用
|
|
即可向USB主机端发送数据。当然,data和data_length都必须符合USB的描述以及配置。具体请参见USB的文档:https://www.usb.org