USB读卡器实验

22.1 usb概述usb是英文universal serial bus(通用串行总线)的缩写,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在pc领域的接口技术。usb接口支持设备的即插即用和热插拔功能。是在1994年底由英特尔、康柏、ibm、microsoft等多家公司联合提出的。发展到现在已经有usb1.0/1.1/2.0/3.0/3.1等多个版本。目前用的最多的就是usb2.0和usb3.0,usb3.1目前已经开始普及。stm32f103自带的usb符合usb2.0规范。标准usb共四根线组成,除vcc和gnd外,另外为d+,d-,这两根数据线采用的是差分电压的方式进行数据传输的。在usb主机上,d-和d+都是接了15k的电阻到低的,所以在没有设备接入的时候,d+、d-均是低电平。而在usb设备中,如果是高速设备,则会在d+上接一个1.5k的电阻到vcc,而如果是低速设备,则会在d-上接一个1.5k的电阻到vcc。这样当设备接入主机的时候,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速设备。
stm32f1自带一个usb从机控制器,符合usb规范通信,pc主机和微控制器之间的数据传输是通过共享一个专用的数据缓冲区来完成的,该数据缓冲区能被usb外设直接访问,这块专用数据缓冲区的大小由所使用的端点数目和每个端点最大的数据分组大小所决定,每个端点最大可使用512字节缓冲区,最多可用于16个单向或8个双向端点。
usb模块同pc主机通信,根据usb规范实现令牌分组的检测,数据发送/接收的处理,和握手分组的处理。整个传输的格式由硬件完成,其中包括crc的生成和校验。每个端点都有一个缓冲区描述块,描述该端点使用的缓冲区地址、大小和需要传输的字节数。当usb模块识别出一个有效的功能/端点的令牌分组时,(如果需要传输数据并且端点已配置)随之发生相关的数据传输。usb模块通过一个内部的16位寄存器实现端口与专用缓冲区的数据交换。在所有的数据传输完成后,如果需要,则根据传输的方向,发送或接收适当的握手分组。在数据传输结束时,usb模块将触发与端点相关的中断,通过读状态寄存器和/或者利用不同的中断来处理。usb设备架构如图所示。
usb的中断映射单元:将可能产生中断的usb事件映射到三个不同的nvic请求线上:
(1)usb低优先级中断(通道20):可由所有usb事件触发(正确传输,usb复位等)。在处理中断前应首先确定中断源。
(2)usb高优先级中断(通道19):仅由同步和双缓冲批量传输的正确传输事件触发,为保证最大的传输速率。
(3)usb唤醒中断(通道42):由usb挂起模式的唤醒事件触发。
注:usb和can共用一个专用的512字节的sram存储器用于数据的发送和接收,因此不能同时使用usb和can(共享的sram被usb和can模块互斥地访问)。usb和can可以同时用于一个应用中但不能在同一个时间使用。
22.2 实验例程如果需要正常的使用stm32f1系列的usb模块,就需要编写usb驱动程序,这部分程序非常复杂,需要了解整个usb通信的详细过程,针对这个问题,st公司提供了一个官方的usb驱动库,用户可以通过直接移植官方驱动库来实现usb读写控制。
我们现在直接利用官方的usb驱动源码来通过计算机进行sd卡和flash的读写,这里我们需要对官方源码进行一些修改,用于实现这个效果。
22.2.1 usb源码概述usb mass storage类支持两个传输协议:
(1)bulk-only传输(bot)
(2)control/bulk/interrupt传输(cbi)
massstorage类规范定义了两个类规定的请求:get_max_lun和massstoragereset,所有的massstorage类设备都必须支持这两个请求。
(1)get_max_lun(bmrequesttype=10100001 bandb request=11111110b)用来确认设备支持的逻辑单元数。maxlun的值必须是0~15。注意:lun是从0开始的。主机不能向不存在的lun发送cbw,本章我们定义maxlun的值为1,即代表2个逻辑单元。
(2)massstoragereset(bmrequesttype=00100001 bandb request=11111111b)用来复位massstorage设备及其相关接口。
支持bot传输的massstorage设备接口描述符要求如下:
(1)接口类代码binterfaceclass=08h,表示为massstorage设备。
(2)接口类子代码binterfacesubclass=06h,表示设备支持scsiprimarycommand-2(spc-2)。
(3)协议代码binterfaceprotocol有3种:0x00、0x01、0x50,前两种需要使用中断传输,最后一种仅使用批量传输(bot)。
(4)支持bot的设备必须支持最少3个endpoint:control,bulk-in和bulk-out。usb2.0的规范定义了控制端点0。bulk-in端点用来从设备向主机传送数据(本章用端点1实现)。bulk-out端点用来从主机向设备传送数据(本章用端点2实现)。
st官方的例程是通过usb来读写sd卡(sdio方式)和nand falsh,支持2个逻辑单元,我们在官方例程的基础上,只需要修改sd驱动部分代码,并将对nand falsh的操作修改为对spi falsh的操作。只要这两步完成了,剩下的就比较简单了,对底层磁盘的读写,都是在mass_mal.c文件实现的,所以我们只需要修改该函数的mal_init、mal_write、mal_read和mal_getstatus等4个函数,与我们的sd卡和spi falsh对应起来即可。
22.2.2 源码移植过程(1)需要添加的文件如下表所示。
文件名目录功能
usb_core.c ....\\usb\\core 用于处理usb2.0协议
usb_init.c 用于usb控制器的初始化
usb_int.c 负责usb的中断处理
usb_mem.c 负责处理pma数据,即stm32内部用于usb/can的专用数据缓冲区
usb_regs.c 负责usb控制寄存器的底层操作
usb_sil.c 为usb端点提供特殊简化的读写访问函数
usb_desc.c ...\\usb\\config 用于虚拟通信端口描述符的处理
usb_endp.c 用于非控制传输,处理正确传输中断回调函数
usb_istr.c 用于处理usb中断
usb_prop.c 用于处理所有虚拟通信端口相关事件,包括初始化,复位等
usb_pwr.c 用于管理usb的电源状态
usb_scsi.c 与scsi命令相关的所有处理
scsi_data.c 定义了scsi数据
memory.c 定义usb通信的存储区读写函数
mass_mal.c 定义了usb通信的读写操作底层函数接口
usb_bot.c 定义了bot传输协议
(2)usb_prop.c文件修改
原文件
修改后文件
(3)memory.h文件修改
(4)mass_mal.h文件修改
(5)memory.c文件修改
(6)usb_bot.c文件修改
(7)mass_mal.c文件重写
#include platform_config.h
#include mass_mal.h
#include sdio_sdcard.h
#include w25q128.h
long long mass_memory_size[ max_lun+1 ] ;
u32 mass_block_size[ max_lun+1 ] ;
u32 mass_block_count[ max_lun+1 ] ;
uint16_t mal_init( uint8_t lun )
{
u16 status=mal_ok ; switch( lun ) { case 0: break; case 1: break; default:return mal_fail ; } return status ;}
uint16_t mal_write(uint8_t lun, uint64_t memory_offset, uint32_t *writebuff, uint16_t transfer_length)
{
u8 sta ; switch( lun ) { //磁盘0为 spi flash盘 case 0: sta = 0 ; w25qxx_write( ( u8* )writebuff, memory_offset, transfer_length ) ; break ; //磁盘1为sd卡 case 1: sta = sd_writedisk( ( u8* )writebuff, memory_offset>>9, transfer_length>>9 ) ; break ; default: return mal_fail ; } if( sta!=0 ) return mal_fail ; return mal_ok ;}
uint16_t mal_read( uint8_t lun, uint64_t memory_offset, uint32_t *readbuff, uint16_t transfer_length )
{
u8 sta ; switch( lun ) { //磁盘0为 spi flash盘 case 0 : sta = 0 ;w25qxx_read( ( u8* )readbuff, memory_offset, transfer_length ) ;
break; //磁盘1为sd卡 case 1 :sta = sd_readdisk( ( u8* )readbuff, memory_offset>>9, transfer_length>>9 ) ;
break; default:return mal_fail ; } if( sta!=0 ) return mal_fail ; return mal_ok ;}
uint16_t mal_getstatus( uint8_t lun )
{
switch( lun ){ case 0:return mal_ok; case 1:return mal_ok; default:return mal_fail;}}
(8)hw_config.h文件重写
#ifndef hw_config_h
#define hw_config_h
#include platform_config.h
#include usb_type.h
typedef enum
{
disable = 0, enable = 1}functionalstate;
#define bulk_max_packet_size 0x00000040 //包大小,最大64字节
void led_rw_on( void ) ; //led开启
void led_rw_off( void ) ; //led关闭
void set_usbclock( void ) ; //usb时钟配置函数
void enter_lowpowermode( void ) ; //usb进入低功耗模式
void leave_lowpowermode( void ) ; //usb退出低功耗模式
void usb_interrupts_config( void ) ; //usb中断配置
void usb_port_set( u8 enable ) ; //usb使能
void get_serialnum( void ) ; //获取stm32的唯一id
#endif
(9)hw_config.c文件重写
#include usb_lib.h
#include mass_mal.h
#include usb_desc.h
#include usb_pwr.h
#include usb_lib.h
#include usb_istr.h
void usb_notconfigured_led()
{
}
void usb_cable_config( functionalstate newstate )
{
}
void led_rw_off()
{
}
void led_rw_on()
{
}
void usbwakeup_irqhandler()
{
exti->pr |= 1void usb_interrupts_config()
{
exti->imr |= 1crh |= 0x00033000 ; paout( 12 ) = 0 ; }}
void inttounicode( u32 value, u8 *pbuf, u8 len )
{
u8 idx ; for( idx=0; idx}
void get_serialnum()
{
u32 device_serial0, device_serial1, device_serial2 ; device_serial0 = *( u32* )0x1ffff7e8 ; device_serial1 = *( u32* )0x1ffff7ec ; device_serial2 = *( u32* )0x1ffff7f0 ; device_serial0 += device_serial2 ; if( device_serial0!=0 ) { inttounicode( device_serial0, &mass_stringserial[ 2 ] , 8 ) ; inttounicode( device_serial1, &mass_stringserial[ 18 ], 4 ) ; }}
(10)platform_config.h文件重写
#ifndef platform_config_h
#define platform_config_h
#include sys.h
#define use_stm3210e_eval //当前使用的版本
#endif
(11)usb_pwr.c文件修改(改写suspend函数)
void suspend(void)
{
uint32_t i=0 ; uint16_t wcntr ; __io uint32_t savepwr_cr=0 ; wcntr = _getcntr() ;for( i=0; i<8; i++ ) ep[ i ] = _getendpoint( i ) ; wcntr |= cntr_resetm ; _setcntr( wcntr ) ; wcntr |= cntr_fres ; _setcntr( wcntr ) ; wcntr &= ~cntr_fres ; _setcntr( wcntr ) ; while( ( _getistr()&istr_reset )==0 ) ; _setistr( ( uint16_t )clr_reset ) ; for( i=0; i10 ) bdevicestate = unconnected ; //2s内没收到在线标记,代表usb被拔出了 } usb_status_reg = 0 ; } }}

如何处理好人机关系,以更好地享受人工智能的红利
如何使用MDO查找无线嵌入式系统中的噪声来源
保持永磁电机正常工作技术要点有哪些
华润微完成50亿元足额募资 行业龙头获市场高度认可!
数据中心小母线监控方案
USB读卡器实验
Lora高智能可燃气感探测器的特点
电机驱动着世界运转
苹果发布会没有iPhone12 二手市场iPhone竟涨价了
移远入选年度车载通讯模组领军供应商 广和通加速5G超宽带应用落地
面板价格的涨跌,对彩电整机企业的影响格外明显
详细介绍DDR模块在SoC设计中的应用
静水压测定仪做抗渗水性的测定步骤介绍
基于GSM的超远程水泵控制系统电路设计
WLAN已被证明无法与移动通信服务相抗衡
高频芯片主要用于发动机引擎的标识和管理
基于LabVIEW和PXI平台设计的6-DOF并联机器人控制
氢燃料电池与储能电池并不存在替代关系
【访谈】汽车电子的新动向
2017小米在CES!不只是白色版小米MIX和电视还有多款新品