第五十六章 USB读卡器(Slave)实验
[mw_shl_code=c,true]1.硬件平台:正点原子探索者STM32F407开发板
2.软件平台:MDK5.1
3.固件库版本:V1.4.0[/mw_shl_code]
STM32F407系列芯片都自带了
USB OTG FS和
USB OTG HS(
HS需要外扩高速
PHY芯片实现,速度可达
480Mbps),支持
USB Host和
USB Device,探索者
STM32F4开发板没有外扩高速
PHY芯片,仅支持
USB OTG FS(
FS,即全速,
12Mbps),所有
USB相关例程,均使用
USB OTG FS实现。
本章,我们将向大家介绍如何利用
USB OTG FS在
ALIENTEK探索者
STM32F4开发板实现一个
USB读卡器。本章分为如下几个部分:
56.1 USB简介
56.2 硬件设计
56.3 软件设计
56.4 下载验证
56.1 USB简介
USB ,是英文
Universal Serial BUS(通用串行总线)的缩写,而其中文简称为“通串线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在
PC领域的接口技术。
USB接口支持设备的即插即用和热插拔功能。
USB是在
1994年底由英特尔、康柏、
IBM、
Microsoft等多家公司联合提出的。
USB发展到现在已经有
USB1.0/1.1/2.0/3.0等多个版本。目前用的最多的就是
USB1.1和
USB2.0,
USB3.0目前已经开始普及。
STM32F407自带的
USB符合
USB2.0规范。
标准
USB共四根线组成
,除
VCC/GND外,另外为
D+和
D-,这两根数据线采用的是差分电压的方式进行数据传输的。在
USB主机上,
D-和
D+都是接了
15K的电阻到地的,所以在没有设备接入的时候,
D+、
D-均是低电平。而在
USB设备中,如果是高速设备,则会在
D+上接一个
1.5K的电阻到
VCC,而如果是低速设备,则会在
D-上接一个
1.5K的电阻到
VCC。这样当设备接入主机的时候,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速设备。接下来,我们简单介绍一下
STM32的
USB控制器。
STM32F407系列芯片自带有
USB OTG FS(全速)和
USB OTG HS(高速),其中
HS需要外扩高速
PHY芯片实现,我们这里不做介绍。
STM32F407的
USB OTG FS是一款双角 {MOD}设备
(DRD) 控制器,同时支持从机功能和主机功能,完全符合
USB 2.0规范的
On-The-Go补充标准。此外,该控制器也可配置为“仅主机”模式或“仅从机”
模式,完全符合
USB 2.0规范。在主机模式下,
OTG FS支持全速(
FS,
12 Mb/s)和低速(
LS,
1.5 Mb/s)收发器,而从机模式下则仅支持全速(
FS,
12 Mb/s)收发器。
OTG FS同时支持
HNP和
SRP。
STM32F407的
USB OTG FS主要特性可分为三类:通用特性、主机模式特性和从机模式特性。
1,通用特性
?
经
USB-IF认证,符合通用串行总线规范第
2.0版
?
集成全速
PHY,且完全支持定义在标准规范
OTG补充第
1.3版中的
OTG协议
1,支持
A-B器件识别(
ID线)
2,支持主机协商协议
(HNP)和会话请求协议
(SRP)
3,允许主机关闭
VBUS以在
OTG应用中节省电池电量
4,支持通过内部比较器对
VBUS电平采取监控
5,支持主机到从机的角 {MOD}动态切换
?
可通过软件配置为以下角 {MOD}:
1, 具有
SRP功能的
USB FS从机(
B器件)
2, 具有
SRP功能的
USB FS/LS主机(
A器件)
3,
USB On-The-Go全速双角 {MOD}设备
?
支持
FS SOF和
LS Keep-alive令牌
1,
SOF脉冲可通过
PAD输出
2,
SOF脉冲从内部连接到定时器
2 (TIM2)
3,可配置的帧周期
3, 可配置的帧结束中断
?
具有省电功能,例如在
USB挂起期间停止系统、关闭数字模块时钟、对
PHY和
DFIFO电源加以管理
?
具有采用高级
FIFO控制的
1.25 KB专用
RAM
1,可将
RAM 空间划分为不同
FIFO,以便灵活有效地使用
RAM
2,每个
FIFO可存储多个数据包
3,动态分配存储区
4,
FIFO大小可配置为非
2的幂次方值,以便连续使用存储单元
?
一帧之内可以无需要应用程序干预,以达到最大
USB 带宽
2,主机(Host)模式特性
?
通过外部电荷泵生成
VBUS电压。
?
多达
8个主机通道(管道):每个通道都可以动态实现重新配置,可支持任何类型的
USB 传输。
?
内置硬件调度器可:
1,在周期性硬件队列中存储多达
8个中断加同步传输请求
2,在非周期性硬件队列中存储多达
8个控制加批量传输请求
?
管理一个共享
RX FIFO、一个周期性
TX FIFO和一个非周期性
TX FIFO,以有效使用
USB数据
RAM。
3,从机(Slave/Device)模式特性
?
1个双向控制端点
0
?
3个
IN 端点
(EP),可配置为支持批量传输、中断传输或同步传输
?
3个
OUT 端点
(EP),可配置为支持批量传输、中断传输或同步传输
?
管理一个共享
Rx FIFO和一个
Tx-OUT FIFO,以高效使用
USB数据
RAM
?
管理多达
4个专用
Tx-IN
FIFO(分别用于每个使能的
IN EP),降低应用程序负荷支持软断开功能。
STM32F407 USB OTG FS框图如图
56.1.1所示:
图
56.1.1 USB OTG框图
对于
USB OTG FS功能模块,
STM32F4通过
AHB总线访问(
AHB频率必须大于
14.2Mhz),其中
48Mhz的
USB时钟,是来自时钟树图里面的
PLL48CK(和
SDIO共用)。
STM32F4 USB OTG FS的其他介绍,请大家参考《
STM32F4xx中文参考手册》第
30章内容,我们这里就不再详细介绍了。
要正常使用
STM32F4的
USB,就得编写
USB驱动,而整个
USB通信的详细过程是很复杂的,本书篇幅有限,不可能在这里详细介绍,有兴趣的朋友可以去看看电脑圈圈的《圈圈教你玩
USB》这本书,该书对
USB通信有详细讲解。如果要我们自己编写
USB驱动,那是一件相当困难的事情,尤其对于从没了解过
USB的人来说,基本上不花个一两年时间学习,是没法搞定的。不过,
ST提供了我们一个完整的
USB OTG 驱动库(包括主机和设备),通过这个库,我们可以很方便的实现我们所要的功能,而不需要详细了解
USB的整个驱动,大大缩短了我们的开发时间和精力。
ST提供的
USB OTG库,可以在
: http://www.stmcu.org/download/index.php?act=ziliao
&id=150这里下载到(
UM1021)。不过,我们已经帮大家下载到开发板光盘:
8,
STM32参考资料àSTM32 USB 学习资料,文件名:stm32_f105-07_f2_f4_usb-host-device_lib.zip。该库包含了
STM32F4 USB 主机(
Host)和从机(
Device)驱动库,并提供了
10个例程供我们参考,如图
56.1.2所示:
图
56.1.2 ST提供的
USB OTG例程
如图
56.1.2所示,
ST提供了
3类例程:①即设备类(
Device,即
Slave)、②主从一体类(
Host_Device)和③主机类(
Host),总共
10个例程。整个USB OTG库还有一个说明文档:
CD00289278.pdf(在光盘有提供
),即
UM1021,该文档详细介绍了
USB
OTG库的各个组成部分以及所提供的例程使用方法,有兴趣学习
USB的朋友,这个文档是必须仔细看的。
这
10个例程,虽然都是基于官方
EVAL板的,但是很容易移植到我们的探索者
STM32F407开发板上,本章我们就是移植:
STM32_USB-Host-Device_Lib_V2.1.0ProjectUSB_Device_
ExamplesMSC这个例程,以实现
USB读卡器功能。
56.2 硬件设计
本章实验功能简介:开机的时候先检测SD卡和SPI FLASH是否存在,如果存在则获取其容量,并显示在LCD上面(如果不存在,则报错)。之后开始USB配置,在配置成功之后就可以在电脑上发现两个可移动磁盘。我们用DS1来指示USB正在读写,并在液晶上显示出来,同样,我们还是用DS0来指示程序正在运行。
所要用到的硬件资源如下:
1) 指示灯
DS0 、
DS1
2) 串口
3) TFTLCD模块
4) SD卡
5) SPI FLASH
6) USB SLAVE接口
前面
5部分,在之前的实例中都介绍过了,我们在此就不介绍了。接下来看看我们电脑
USB与
STM32的
USB SLAVE连接口。
ALIENTEK探索者
STM32F4开发板采用的是
5PIN的
MiniUSB接头,用来和电脑的
USB相连接,连接电路如图
56.2.1所示:
图
56.2.1 MiniUSB接口与
STM32的连接电路图
从上图可以看出,
USB座没有直接连接到
STM32F4上面,而是通过
P11转接,所以我们需要通过跳线帽将
PA11和
PA12分别连接到
D-和
D+,如图
56.2.2所示:
图
56.2.2 硬件连接示意图
不过这个
MiniUSB座和
USB-A座(
USB_HOST)是共用
D+和
D-的,所以他们不能同时使用。这个在使用的时候,要特别注意!!本实验测试时,
USB_HOST不能插入任何
USB设备!
56.3 软件设计
本章,我们在:实验
38 SD卡实验 的基础上修改,代码移植自
ST官方例程:
STM32_USB-
Host-Device_Lib_V2.1.0ProjectUSB_Device_ExamplesMSC,我打开该例程即可知道
USB相关的代码有哪些,如图
56.3.1所示:
图
56.3.1 ST官方例程
USB相关代码
有了这个官方例程做指引,我们就知道具体需要哪些文件,从而实现本章例程。
首先,在本章例程(即实验
38 SD卡实验)的工程文件夹下面,新建
USB文件夹,并拷贝官方
USB驱动库相关代码到该文件夹下,即拷贝:光盘à
8,
STM32参考资料à
STM32 USB 学习资料à
STM32_USB-Host-Device_Lib_V2.1.0à
Libraries文件夹下的
STM32_USB_Device_Libr
ary、
STM32_USB_HOST_Library和
STM32_USB_OTG_Driver等三个文件夹的源码到该文件夹下面。
然后,在
USB文件夹下,新建
USB_APP文件夹存放
MSC实现相关代码,即:
STM32_USB
-Host-Device_Lib_V2.1.0à
Projectà
USB_Device_Examplesà
MSCà
src下的部分代码:
usb_bsp.c
、
usbd_storage_msd.c、
usbd_desc.c和
usbd_usr.c等
4个
.c文件,同时拷贝
STM32_USB-Host-Device
_Lib_V2.1.0à
Projectà
USB_Device_Examplesà
MSCà
inc下面的:
usb_conf.h、
usbd_conf.h和
usbd_desc.h等三个文件到
USB_APP文件夹下,最后
USB_APP文件夹下的文件如图
56.3.2所示:
图
56.3.2 USB_APP代码
之后,根据
ST官方
MSC例程,在我们本章例程的基础上新建分组添加相关代码,具体细节,这里就不详细介绍了,添加好之后,如图
56.3.3所示:
图
56.3.3 添加
USB驱动等相关代码
移植时,我们重点要修改的就是
USB_APP文件夹下面的代码。其他代码(
USB_OTG和
USB_DEVICE文件夹下的代码)一般不用修改。
usb_bsp.c提供了几个
USB库需要用到的底层初始化函数,包括:
IO设置、中断设置、
VBUS配置以及延时函数等,需要我们自己实现。
USB Device(
Slave)和
USB Host共用这个
.c文件。
usbd_desc.c提供了
USB设备类的描述符,直接决定了
USB设备的类型、断点、接口、字符串、制造商等重要信息。这个里面的内容,我们一般不用修改,直接用官方的即可。注意,这里:
usbd_desc.c里面的:
usbd即
device类,同样:
usbh即
host类,所以通过文件名我们可以很容易区分该文件是用在
device还是
host,而只有
usb字样的那就是
device和
host可以共用的。
usbd_usr.c提供用户应用层接口函数,即
USB设备类的一些回调函数,当
USB状态机处理完不同事务的时候,会调用这些回调函数,我们通过这些回调函数,就可以知道
USB当前状态,比如:是否枚举成功了?是否连接上了?是否断开了?等,根据这些状态,用户应用程序可以执行不同操作,完成特定功能。
usbd_storage_msd.c提供一些磁盘操作函数,包括支持的磁盘个数,以及每个磁盘的初始化和读写等函数。本章我们设置了
2个磁盘:
SD卡和
SPI FLASH。
以上
4个
.c文件里面的函数,基本上都是以回调函数的形式,被
USB驱动库调用的。这些代码的具体修改过程,我们这里不详细介绍,请大家参考光盘本例程源码,这里只提几个重点地方讲解下:
1,要使用
USB OTG FS,必须在
MDK编译器的全局宏定义里面,定义:
USE_USB_OTG_FS宏,如图
56.3.4所示:
图
56.3.4 定义全局宏
USE_USB_OTG_FS
2,因为探索者
STM32F407开发板没有用到
VUSB电压检测,所以要在
usb_conf.h里面,将宏定义:
#define VBUS_SENSING_ENABLED,屏蔽掉。
3,通过修改
usbd_conf.h里面的
MSC_MEDIA_PACKET定义值大小,可以一定程度提高
USB读写速度(越大越快),本例程我们设置
12*1024,也就是
12K大小。
4,官方例程不支持大于
4G的
SD卡,得修改
usbd_msc_scsi.c里面的
SCSI_blk_addr类型为
uint64_t,才可以支持大于
4G的卡,官方默认是
uint32_t,最大只能支持
4G卡。注意:
usbd_msc_scsi.c文件,是只读的,得先修改属性,去掉只读属性,才可以更改。
以上
4点,就是我们移植的时候需要特别注意的,其他我们就不详细介绍了(
USB相关源码解释,请参考:CD00289278.pdf这个文档),最后修改
main.c里面代码如下:
USB_OTG_CORE_HANDLE USB_OTG_dev;
extern vu8 USB_STATUS_REG; //USB状态
extern vu8 bDeviceState; //USB连接 情况
int main(void)
{
u8
offline_cnt=0; u8 tct=0;
u8
Divece_STA; u8 USB_STA;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组
2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为
115200
LED_Init(); //初始化
LED
LCD_Init(); //LCD初始化
KEY_Init(); //按键初始化
W25QXX_Init(); //初始化
W25Q128
POINT_COLOR=RED;//设置字体为红 {MOD}
LCD_ShowString(30,50,200,16,16,"Explorer
STM32F4");
LCD_ShowString(30,70,200,16,16,"USB
Card Reader TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,"2014/7/21");
if(SD_Init())LCD_ShowString(30,130,200,16,16,"SD
Card Error!"); //检测
SD卡错误
else
//SD 卡正常
{
LCD_ShowString(30,130,200,16,16,"SD
Card Size: MB");
LCD_ShowNum(134,130,SDCardInfo.CardCapacity>>20,5,16); //显示
SD卡容量
}
if(W25QXX_ReadID()!=W25Q128)
LCD_ShowString(30,130,200,16,16,"W25Q128 Error!"); //检测
W25Q128错误
else
LCD_ShowString(30,150,200,16,16,"SPI FLASH Size:12MB"); //SPI FLASH 正常
LCD_ShowString(30,170,200,16,16,"USB
Connecting...");//提示正在建立连接
USBD_Init(&USB_OTG_dev,USB_OTG_FS_CORE_ID,&USR_desc,&USBD_MSC_cb,
&USR_cb);
delay_ms(1800);
while(1)
{
delay_ms(1);
if(USB_STA!=USB_STATUS_REG)//状态改变了
{
LCD_Fill(30,190,240,190+16,WHITE);//清除显示
if(USB_STATUS_REG&0x01)//正在写
{
LED1=0;
LCD_ShowString(30,190,200,16,16,"USB
Writing...");//USB正在写数据
}
if(USB_STATUS_REG&0x02)//正在读
{
LED1=0;
LCD_ShowString(30,190,200,16,16,"USB
Reading...");//USB正在读数据
}
if(USB_STATUS_REG&0x04)
LCD_ShowString(30,210,200,16,16,"USB Write Err ");//提示写入错误
else
LCD_Fill(30,210,240,210+16,WHITE);//清除显示
if(USB_STATUS_REG&0x08)
LCD_ShowString(30,230,200,16,16,"USB Read Err ");//提示读出错误
else
LCD_Fill(30,230,240,230+16,WHITE);//清除显示
USB_STA=USB_STATUS_REG;//记录最后的状态
}
if(Divece_STA!=bDeviceState)
{
if(bDeviceState==1)LCD_ShowString(30,170,200,16,16,"USB
Connected ");
else
LCD_ShowString(30,170,200,16,16,"USB DisConnected ");//USB被拔出了
Divece_STA=bDeviceState;
}
tct++;
if(tct==200)
{
tct=0;
LED1=1;
LED0=!LED0;//提示系统在运行
if(USB_STATUS_REG&0x10)
{
offline_cnt=0;//USB连接了
,则清除
offline计数器
bDeviceState=1;
}else//没有得到轮询
{
offline_cnt++;
if(offline_cnt>10)bDeviceState=0;//2s内没收到在线标记
,则
USB被拔出了
}
USB_STATUS_REG=0;
}
};
}
其中,
USB_OTG_CORE_HANDLE是一个全局结构体类型,用于存储
USB通信中
USB内核需要使用的的各种变量、状态和缓存等,任何
USB通信(不论主机,还是从机),我们都必须定义这么一个结构体以实现
USB通信,这里定义成:
USB_OTG_dev。
然后,
USB初始化非常简单,只需要调用
USBD_Init函数即可,顾名思义,该函数是
USB设备类初始化函数,本章的
USB读卡器属于
USB设备类,所以使用该函数。该函数初始化了
USB设备类处理的各种回调函数,以便
USB驱动库调用。执行完该函数以后,
USB就启动了,所有
USB事务,都是通过
USB中断触发,并由
USB驱动库自动处理。
USB中断服务函数在
usbd_usr.c里面:
//USB OTG 中断服务函数
处理所有
USB中断
void OTG_FS_IRQHandler(void)
{
USBD_OTG_ISR_Handler(&USB_OTG_dev);
}
该函数调用
USBD_OTG_ISR_Handler函数来处理各种
USB中断请求。因此在
main函数里面,我们的处理过程就非常简单,
main函数里面通过两个全局状态变量(
USB_STATUS_REG和
bDeviceState),来判断
USB状态,并在
LCD上面显示相关提示信息。
USB_STATUS_REG在
usbd_storage_msd.c里面定义的一个全局变量,不同的位表示不同状态,用来指示当前
USB的读写等操作状态。
bDeviceState是在
usbd_usr.c里面定义的一个全局变量,
0表示
USB还没有连接;
1表示
USB已经连接。
软件设计部分,就给大家介绍到这里。
56.4 下载验证
在代码编译成功之后,我们下载到探索者
STM32F4开发板上,在
USB配置成功后(假设已经插入
SD卡,
注意:USB数据线,要插在USB_SLAVE口!不是USB_232端口!另外,USB_HOST接口,也不要插入任何设备,否则会干扰!!),
LCD显示效果如图
56.4.1所示:
图
56.4.1 USB连接成功
此时,电脑提示发现新硬件,并开始自动安装驱动,如图
56.4.2所示:
图
56.4.2 USB读卡器被电脑找到
等
USB配置成功后,
DS1不亮,
DS0闪烁,并且在电脑上可以看到我们的磁盘,如图
56.4.3所示:
图
56.4.3 电脑找到
USB读卡器的两个盘符
我们打开设备管理器,在通用串行总线控制器里面可以发现多出了一个
USB 大容量存储设备,同时看到磁盘驱动器里面多了
2个磁盘,如图
56.4.4所示:
图
56.4.4 通过设备管理器查看磁盘驱动器
此时,我们就可以通过电脑读写
SD卡或者
SPI FLASH里面的内容了。在执行读写操作的时候,就可以看到
DS1亮,并且会在液晶上显示当前的读写状态。
注意,在对
SPI FLASH操作的时候,最好不要频繁的往里面写数据,否则很容易将
SPI FLASH写爆!!
实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm
正点原子探索者STM32F407开发板购买地址:http://item.taobao.com/item.htm?id=41855882779
一周热门 更多>