CH32V103应用教程——USB模拟U盘 本章教程主要使用CH32V103 USB模拟U盘设备,此程序是移植而来,仅供参考。
1、USB简介及相关函数介绍 关于USB具体介绍,可参考前面章节。
2、硬件设计 本章教程主要进行USB模拟U盘设备,仅需用到开发板USB口。
3、软件设计 本章程序全在主函数中进行,具体程序如下: main.c文件 /********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.0.0
* Date : 2019/10/15
* Description : Main program body.
*******************************************************************************/
#include "debug.h"
#include "string.h"
#define DevEP0SIZE 0x40
/* Device Descriptor */
const UINT8 MyDevDescr[] =
{
0x12, //设备描述符长度,18字节
0x01, //描述符类型,0x01为设备描述符
0x10, 0x01, //本设备所使用USB版本协议,因为是小端结构,所以低字节在前,即USB1.1版本为0x10,0x01,USB2.0为0x00,0x02
0x00, //类代码,此处不在设备描述符中定义设备类,而在接口描述符中定义设备类。对于大多数标准的USB设备类,该字段通常设置为0,而在接口描述符中的bInterfaceClass中指定接口所实现的功能
0x00, //子类代码,当类代码bDeviceClass为0时,下面的子类代码bDeviceSubClass也必须为0。
0x00, //设备所使用的协议,协议代码由USB协会规定。当该字段为0时,表示设备不使用类所定义的协议。
DevEP0SIZE, //端点0的最大包长,可以取值8、16、32、64,此处为64字节
0x86, 0x1A, //厂商ID
0x22, 0x57, //产品设备ID
0x00, 0x01, //设备版本号
0x01, //描述厂商的字符串索引值。当该值为0时,表示没有厂商字符串
0x02, //描述产品的字符串索引值。当该值为0时,表示没有产品字符串
0x03, //描述设备的序列号字符串索引值。当该值为0时,表示没有序列号字符串
0x01, //可能的配置数,通常为1
};
/* Configration Descriptor */
const UINT8 MyCfgDescr[] =
{
//配置描述符
0x09, //配置描述符长度,标准USB配置描述符长度为9字节
0x02, //描述符类型,配置描述符为0x02
0x20, 0x00, //配置描述符集合总长度,32字节
0x01, //该配置所支持的接口数,1个接口
0x01, //表示该配置的值
0x00, //描述该配置的字符串的索引值,0x00表示没有字符串
0xA0, //描述设备的一些属性,如供电方式和唤醒等,0xA0表示设备总线供电且支持远程唤醒
0x32, //设备需要从总线获取的最大电流量,0x32表示最大电流100ma
//接口描述符,接口描述符不能单独返回,必须附着在配置描述符后一并返回
0x09, //接口描述符长度,标准的USB接口描述符长度为9字节
0x04, //描述符类型,接口描述符为0x04
0x00, //该接口的编号,从0开始,此处为0x00
0x00, //该接口的备用编号,通常设置为0
0x02, //该接口所使用的端点数,0x02表示使用2个端点。如果该字段为0,则表示没有非0端点,只使用默认的控制端点
0x08, //该接口所使用的类,0x08为大容量存储设备类
0x06, //该接口所使用的子类,0x06,即SCSI透明命令集
0x50, //该接口所使用的协议,协议代码有3种:0x00、0x01、0x50,前两种需要使用中断传输,最后一种仅使用批量传输
0x00, //该接口的字符串的索引值,0x00表示没有字符串
//端点描述符,端点描述符不能单独返回,必须附着在配置描述符后一并返回
0x07, //端点描述符长度,标准的USB端点描述符长度为7字节
0x05, //描述符类型,端点描述符为0x05
0x01, //该端点的地址,0x01表示端点1作为输出,最高位D7为该端点的传输方向,1为输入,0为输出。D3-D0为端点号,可设置为0-7,D6-4保留,设为0.
//关于端点属性,最低两位D1-0表示该端点的传输类型,0为控制传输,1为等时传输,2为批量传输,3为中断传输。
0x02, //该端点的属性,此处为批量传输方式
DevEP0SIZE, 0x00, //该端点支持的最大包长度,此处设置为64字节
0x00, //端点的查询时间
//端点描述符,端点描述符不能单独返回,必须附着在配置描述符后一并返回
0x07, //端点描述符长度,标准的USB端点描述符长度为7字节
0x05, //描述符类型,端点描述符为0x05
0x81, //该端点的地址,0x81表示端点1作为输入,最高位D7为该端点的传输方向,1为输入,0为输出。D3-D0为端点号,可设置为0-7,D6-4保留,设为0.
//关于端点属性,最低两位D1-0表示该端点的传输类型,0为控制传输,1为等时传输,2为批量传输,3为中断传输。
0x02, //该端点的属性,此处为批量传输方式
DevEP0SIZE, 0x00, //该端点支持的最大包长度,此处设置为64字节
0x00, //端点的查询时间
};
const UINT8 MyProductIDInfo[] =
{
0x14,0x03, 0x32,0x00,0x30,0x00,0x31,0x00,0x37,0x00,0x2D,0x00,0x32,0x00,0x2D,0x00,0x32,0x00,0x35,0x00
};
/* Language Descriptor */
const UINT8 MyLangDescr[] = { 0x04, 0x03, 0x09, 0x04 };
/* Manufactor Descriptor */
const UINT8 MyManuInfo[] = { 0x0A,0x03,0x5F,0x6c,0xCF,0x82,0x81,0x6c,0x52,0x60 };
/* Product Information */
const UINT8 MyProdInfo[] = {0x14,0x03,0x43,0x00,0x48,0x00,0x35,0x00,0x35,0x00,0x34,0x00,0x5F,0x00,0x43,0x00,0x44,0x00,0x43,0x00, };
//Get Max LUN 请求,该字节表示设备有多少个逻辑单元,值为0时表示有一个逻辑单元,值为1时表示有两个逻辑单元,以此类推,最大可以取15
//定义一个最大逻辑单元的变量,跟描述符类型一样,使用数组的方式来定义,尽管他只有一个元素。
const UINT8 MAX_LUN[] = {0};
//INQUIRY inform
const UINT8 DBINQUITY[]=
{
0x00, //Peripheral Device Type
0x80, //
0x02 , //ISO/ECMA
0x02 , //
0x1f , //Additional Length
00 , //Reserved
00 , //Reserved
00 , //Reserved
'w' , //Vendor Information
'c' , //
'h' , //
'.' , //
'c' , //
'n' , //
' ' , //
' ' , //
0xc7, //Product Identification
0xdf, //
0xba, //
0xe3, //
0xb5, //
0xe7, //
0xd7, //
0xd3, //
0x55, //
0xc5, //
0xcc, //
0xb7, //
0xbd, //
0xb0, //
0xb8, //
0x00, //
'1' , //Product Revision Level
'.' , //
'1' , //
'0' //
};
#define NUMOFBLOCK 0x40
#define LASTLGCBLOCK 0x3f
const UINT8 DBCAPACITY[]={(LASTLGCBLOCK>>24)&0xFF,(LASTLGCBLOCK>>16)&0xFF,(LASTLGCBLOCK>>8)&0xFF,LASTLGCBLOCK&0xFF,0x00,0x00,0x02,0x00};
const UINT8 modesense3F[]={0x0b, 0x00, 0x00/*0x80*/, 0x08 , (NUMOFBLOCK>>24)&0xFF,(NUMOFBLOCK>>16)&0xFF,(NUMOFBLOCK>>8)&0xFF,NUMOFBLOCK&0xFF,0x00, 0x00, 0x02, 0x00 }; //写保护(0x80换成0x00可以去除写保护)
//DBR(DOS Boot Record):磁盘操作系统引导记录
//DBR是每个逻辑分区的一个引导记录,里面记录了该分区的众多重要信息以及引导代码,所以十分重要。在U盘系统中,必须有DBR
//DBR占据逻辑分区的0扇区,大小通常为512字节,DBR各个部分的意义见《圈圈教你玩USB》
const UINT8 DBR[512]=
{
0xeb,0x3c,0x90,0x4d,0x53,0x44,0x4f,0x53, 0x35,0x2e,0x30,0x00,0x02,0x01,0x06,0x00,
0x02,0x00,0x02,NUMOFBLOCK&0xff,(NUMOFBLOCK>>8)&0xff,0xf8,0x01,0x00, 0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x80,0x00,0x29,0xc3, 0xa5,0x20,0xd8,0x4e,0x4f,0x20,0x4e,0x41,
0x4d,0x45,0x20,0x20,0x20,0x20,0x46,0x41, 0x54,0x31,0x32,0x20,0x20,0x20,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x55,0xaa,
};
//FAT(File Allocation Table):文件分配表
//在DBR之后,就是FAT区(通常有两个,一个为副本)
const UINT8 FAT[512]=
{
0xF8,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
const UINT8 ZERO[512]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
//UFI通讯
#define FORMAT_UNIT 0x04
#define INQUIRY 0x12
#define FORMATCAP 0x23
#define MODE_SELECT 0x15
#define MODE_SENSE5 0x5A
#define MODE_SENSE 0x1A
#define PER_RES_IN 0x5E
#define PER_RES_OUT 0x5F
#define PRE_OR_MED 0x1E
#define READ 0x28
#define READ_CAPACITY 0x25
#define RELEASE 0x17
#define REQUEST_SENSE 0x03
#define RESERVE 0x16
#define STA_STO_UNIT 0x1B
#define SYN_CACHE 0x35
#define TEST_UNIT 0x00
#define VERIFY 0x2F
#define WRITE 0x2A
#define WRITE_BUFFER 0x3B
typedef union _CBWCB
{
unsigned char buf1[16];
}CBWCB;
typedef union _MASS_PARA
{
unsigned char buf[64];
struct _SENSE
{
unsigned char ErrorCode;
unsigned char Reserved1;
unsigned char SenseKey;
unsigned char Information[4];
unsigned char AddSenseLength;
unsigned char Reserved2[4];
unsigned char AddSenseCode;
unsigned char AddSenseCodeQua;
unsigned char Reserved3[4];
}Sense;
struct _CBW
{
unsigned char dCBWsig[4];
unsigned char dCBWTag[4];
unsigned long dCBWDatL;
unsigned char bmCBWFlags;
unsigned char bCBWLUN;
unsigned char bCBWCBLength;
CBWCB cbwcb;
}cbw;
struct _CSW
{
unsigned char buf2[13];
}csw;
}MASS_PARA;
union {
unsigned long mDataLength; //数据长度
unsigned char mdataLen[4]; //
} UFI_Length;
unsigned char mdCBWTag[4]; //dCBWTag
MASS_PARA MassPara;
UINT8 CH32BULKUP=0; //数据上传
UINT8 CH32BULKDOWN = 0; //数据下传
UINT8 CH32CSW=0; //CSW上传标志
unsigned char BcswStatus; //CSW状态
unsigned char mSenseKey;
unsigned char mASC;
unsigned char *pBuf;
unsigned long SecNum; //当前操作的扇区号
unsigned char dat_tran_flag = 0;
/**********************************************************/
UINT8 Ready = 0;
UINT8 UsbConfig;
UINT8 SetupReqCode;
UINT16 SetupReqLen;
//cdc参数
UINT8 LineCoding[7]={0x00,0xe1,0x00,0x00,0x00,0x00,0x08}; //初始化波特率为57600,1停止位,无校验,8数据位。
#define SET_LINE_CODING 0x20 // Configures DTE rate, stop-bits, parity, and number-of-character
#define GET_LINE_CODING 0x21 // This request allows the host to find out the currently configured line coding.
#define SET_CONTROL_LINE_STATE 0x22 // This request generates RS-232/V.24 style control signals.
volatile UINT8 UpPoint2_Busy = 0; //上传端点是否忙标志
const UINT8 *pDescr;
/* Endpoint Buffer */
__attribute__ ((aligned(4))) UINT8 EP0_Databuf[64+64+64]; //ep0(64)+ep4_out(64)+ep4_in(64)
__attribute__ ((aligned(4))) UINT8 EP1_Databuf[64+64]; //ep1_out(64)+ep1_in(64)
__attribute__ ((aligned(4))) UINT8 EP2_Databuf[64+64]; //ep2_out(64)+ep2_in(64)
__attribute__ ((aligned(4))) UINT8 EP3_Databuf[64+64]; //ep3_out(64)+ep3_in(64)
void USBHD_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*******************************************************************************
* Function Name : UFI_Hunding
* Description : 命令的分类与识别 UFI CMD
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void UFI_Hunding(void )
{
switch(MassPara.cbw.cbwcb.buf1[0])
{
//查询命令 INQUIRY,操作代码为0x12
case INQUIRY:
pBuf = (UINT8 *)DBINQUITY; //查询U盘信息
if(UFI_Length.mDataLength>sizeof(DBINQUITY)) UFI_Length.mDataLength=sizeof(DBINQUITY);
BcswStatus=0;
mSenseKey=0;
mASC=0;
break;
//主机通常使用WRITE命令往设备写入实际的磁盘数据,操作代码为0x2A
case WRITE:
UFI_Length.mDataLength=(((UINT32)MassPara.cbw.cbwcb.buf1[7]<<8) | (UINT32)MassPara.cbw.cbwcb.buf1[8])*512; //发送长度
SecNum = ((UINT32)MassPara.cbw.cbwcb.buf1[2]<<24) | ((UINT32)MassPara.cbw.cbwcb.buf1[3]<<16) | ((UINT32)MassPara.cbw.cbwcb.buf1[4]<<8) | (UINT32)MassPara.cbw.cbwcb.buf1[5];//起始扇区号
dat_tran_flag = 1;
BcswStatus=0;
mSenseKey=0;
mASC=0;
break;
case PRE_OR_MED:
case TEST_UNIT:
case 0x3b:
CH32BULKDOWN=0;
CH32BULKUP=0;
BcswStatus=0;
mSenseKey=0;
mASC=0;
break;
//主机通常使用READ命令来读取实际的磁盘数据,操作代码为0x28
case READ:
UFI_Length.mDataLength=(((UINT32)MassPara.cbw.cbwcb.buf1[7]<<8) | (UINT32)MassPara.cbw.cbwcb.buf1[8])*512; //发送长度
SecNum = ((UINT32)MassPara.cbw.cbwcb.buf1[2]<<24) | ((UINT32)MassPara.cbw.cbwcb.buf1[3]<<16) | ((UINT32)MassPara.cbw.cbwcb.buf1[4]<<8) | (UINT32)MassPara.cbw.cbwcb.buf1[5];//起始扇区号
dat_tran_flag = 1;
BcswStatus=0;
mSenseKey=0;
mASC=0;
break;
//REQUEST SENSE命令用来探测上一个命令执行失败的原因,主机可在每个命令之后使用该命令来读取命令执行的情况,其命令代码为0x03
case REQUEST_SENSE:
MassPara.Sense.ErrorCode=0x70;
MassPara.Sense.Reserved1=0;
MassPara.Sense.SenseKey=mSenseKey;
MassPara.Sense.Information[0]=0;
MassPara.Sense.Information[1]=0;
MassPara.Sense.Information[2]=0;
MassPara.Sense.Information[3]=0;
MassPara.Sense.AddSenseLength=0x0a;
MassPara.Sense.Reserved2[0]=0;
MassPara.Sense.Reserved2[1]=0;
MassPara.Sense.Reserved2[2]=0;
MassPara.Sense.Reserved2[3]=0;
MassPara.Sense.AddSenseCode=mASC;
MassPara.Sense.AddSenseCodeQua=0;
MassPara.Sense.Reserved3[0]=0;
MassPara.Sense.Reserved3[1]=0;
MassPara.Sense.Reserved3[2]=0;
MassPara.Sense.Reserved3[3]=0;
pBuf=MassPara.buf;
if ( UFI_Length.mDataLength > 18 ) UFI_Length.mDataLength = 18;
BcswStatus=0;
mSenseKey=0;
mASC=0;
break;
//读容量命令,可以让主机读取到当前存储媒介的容量,此命令读到的才是实际的磁盘容量
case READ_CAPACITY:
if ( UFI_Length.mDataLength > sizeof(DBCAPACITY) ) UFI_Length.mDataLength = sizeof(DBCAPACITY);
pBuf=(unsigned char*)DBCAPACITY;
BcswStatus=0;
mSenseKey=0;
mASC=0;
break;
case MODE_SENSE:
if ( UFI_Length.mDataLength > sizeof(modesense3F) ) UFI_Length.mDataLength = sizeof(modesense3F);
pBuf=(unsigned char*)modesense3F;
BcswStatus=0;
mSenseKey=0;
mASC=0;
break;
default:
mSenseKey=5;
if (MassPara.cbw.cbwcb.buf1[0] == FORMATCAP)
mASC=0x20;
else
mASC=0x24;
BcswStatus=1;
if(CH32BULKUP)
{
R8_UEP1_CTRL = R8_UEP1_CTRL | UEP_T_RES_STALL;
}
else
{
R8_UEP1_CTRL = R8_UEP1_CTRL | UEP_R_RES_STALL;
}
break;
}
}
/*******************************************************************************
* Function Name : mCH32UpCsw
* Description : 批量协议状态上传
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void mCH32UpCsw()
{
unsigned char i; //如果数据为0
pBuf=&MassPara.buf[0];
CH32CSW=0; //上传CSW
CH32BULKUP=0; //取消数据上传
MassPara.buf[0]=0x55; //dCSWSignature
MassPara.buf[1]=0x53;
MassPara.buf[2]=0x42;
MassPara.buf[3]=0x53;
MassPara.buf[4]=mdCBWTag[0];
MassPara.buf[5]=mdCBWTag[1];
MassPara.buf[6]=mdCBWTag[2];
MassPara.buf[7]=mdCBWTag[3];
MassPara.buf[8]=UFI_Length.mdataLen[3];
MassPara.buf[9]=UFI_Length.mdataLen[2];
MassPara.buf[10]=UFI_Length.mdataLen[1];
MassPara.buf[11]=UFI_Length.mdataLen[0];
MassPara.buf[12]=BcswStatus;
for(i = 0;i<13;i++)
{
pEP1_RAM_Addr[MAX_PACKET_SIZE+i] = *pBuf;
pBuf++;
}
R8_UEP1_T_LEN = 13;
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK; // 允许上传
}
/*******************************************************************************
* Function Name : mCH32BulkOnly
* Description : 批量协议处理
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void mCH32BulkOnly(){
if(MassPara.buf[0]==0x55){
if(MassPara.buf[1]==0x53){
if(MassPara.buf[2]==0x42){
if(MassPara.buf[3]==0x43){
UFI_Length.mdataLen[3] = *(unsigned char *)(&MassPara.cbw.dCBWDatL); /* 将PC机的低字节在前的16位字数据转换为C51的高字节在前的数据 */
UFI_Length.mdataLen[2] = *( (unsigned char *)(&MassPara.cbw.dCBWDatL) + 1 );
UFI_Length.mdataLen[1] = *( (unsigned char *)(&MassPara.cbw.dCBWDatL) + 2 );
UFI_Length.mdataLen[0] = *( (unsigned char *)(&MassPara.cbw.dCBWDatL) + 3 );
mdCBWTag[0]=MassPara.buf[4];
mdCBWTag[1]=MassPara.buf[5];
mdCBWTag[2]=MassPara.buf[6];
mdCBWTag[3]=MassPara.buf[7]; //取出数据长度
if(UFI_Length.mDataLength){
CH32BULKDOWN=(MassPara.cbw.bmCBWFlags&0X80)?0:1; //判断是上传还是下传数据
CH32BULKUP=(MassPara.cbw.bmCBWFlags&0X80)?1:0;
}
CH32CSW=1;
dat_tran_flag = 0; //数据传输标志位先清零
UFI_Hunding(); //调用UFI协议处理
}
else
R8_UEP1_CTRL = R8_UEP1_CTRL | UEP_T_RES_STALL ;
}
else
R8_UEP1_CTRL = R8_UEP1_CTRL | UEP_T_RES_STALL ;
}
else
R8_UEP1_CTRL = R8_UEP1_CTRL | UEP_T_RES_STALL ;
}
else
R8_UEP1_CTRL = R8_UEP1_CTRL | UEP_T_RES_STALL ;
}
/*******************************************************************************
* Function Name : CH32bulkUpData
* Description : 批量协议上传
* Input : None
* Output : None
* Return : None
*******************************************************************************/
unsigned char file_dat[64]; //文件大小固定64字节
//文件前四个字节(16H 75H 73H 62H) //测试阶段暂用“fusb”
void CH32bulkUpData()
{ //调用端点1上传数据
unsigned char len,i;
unsigned char rootdir = 0; //当前读目录项标志
unsigned char datfield = 0; //数据区标志
//根据读取的地址,分析是否切换pBuf
if(dat_tran_flag)
{
if((UFI_Length.mDataLength&0x1ff)==0)
{
if(SecNum==0)
{
pBuf = (UINT8 *)DBR;
}
else if(SecNum==6 || SecNum==7)
{
pBuf = (UINT8 *)FAT;
}
else
{
pBuf = (UINT8 *)ZERO;
}
if(SecNum == 8)
{
rootdir = 1;
}
if(SecNum==40)
{
datfield = 1;
}
SecNum++;
}
}
if(UFI_Length.mDataLength>MAX_PACKET_SIZE)
{
len=MAX_PACKET_SIZE;
UFI_Length.mDataLength-=MAX_PACKET_SIZE;
}
else
{
len= (unsigned char) UFI_Length.mDataLength;
UFI_Length.mDataLength=0;
CH32BULKUP=0;
}
for(i = 0;i<len;i++)
{
pEP1_RAM_Addr[MAX_PACKET_SIZE+i] = *pBuf;
pBuf++;
}
/* 改写 */
if(rootdir) /* 改写根目录 */
{
memcpy(&pEP1_RAM_Addr[MAX_PACKET_SIZE],"WCH_CFG TXT ",12);
pEP1_RAM_Addr[MAX_PACKET_SIZE+0x1A]=2;
pEP1_RAM_Addr[MAX_PACKET_SIZE+0x1C]= 64;
}
if(datfield) /* 改写数据区 */
{
//ReadDataFlash(0,64,&pEP1_RAM_Addr[MAX_PACKET_SIZE]);
}
R8_UEP1_T_LEN = len;
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK; // 允许上传
}
void mCH32BulkDownData()
{
UINT8 len;
len = R8_USB_RX_LEN;
if(dat_tran_flag) //传输数据
{
if((UFI_Length.mDataLength&0x1ff)==0)
{
if((pEP1_RAM_Addr[0]=='f') && (memcmp(&pEP1_RAM_Addr[1],"usb",3)==0))
{
//FLASH_Write(0,&pEP1_RAM_Addr[0],64); //同时写入Flash
}
}
}
UFI_Length.mDataLength-=len;
if(UFI_Length.mDataLength==0)
{
CH32BULKDOWN=0;
mCH32UpCsw();
}
}
/*******************************************************************************
* Function Name : USB_DevTransProcess
* Description : USB device transfer process.
* Input : None
* Return : None
*******************************************************************************/
void USB_DevTransProcess( void )
{
UINT8 len, length, chtype;
UINT8 intflag, errflag = 0;
intflag = R8_USB_INT_FG;
if( intflag & RB_UIF_TRANSFER )
{
switch ( R8_USB_INT_ST & ( MASK_UIS_TOKEN | MASK_UIS_ENDP ) )
{
case UIS_TOKEN_SETUP:
R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
len = R8_USB_RX_LEN;
if ( len == sizeof( USB_SETUP_REQ ) )
{
SetupReqLen = pSetupReqPak->wLength;
SetupReqCode = pSetupReqPak->bRequest;
chtype = pSetupReqPak->bRequestType;
len = 0;
errflag = 0;
if ( ( pSetupReqPak->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
{
if(SetupReqCode == 0xFE) //GET MAX LUN
{
pDescr = (PUINT8)( &MAX_LUN[0] );
len = 1;
if ( SetupReqLen > len )
{
SetupReqLen = len; // 限制总长度
}
len = SetupReqLen >= DEFAULT_ENDP0_SIZE ? DEFAULT_ENDP0_SIZE : SetupReqLen; // 本次传输长度
memcpy( pEP0_RAM_Addr, pDescr, len ); /* 加载上传数据 */
//SetupLen -= len;
pDescr += len;
}
else
errflag = 0xFF;
}
else
{
switch( SetupReqCode )
{
case USB_GET_DESCRIPTOR:
{
switch( ((pSetupReqPak->wValue)>>8) )
{
case USB_DESCR_TYP_DEVICE:
pDescr = MyDevDescr;
len = MyDevDescr[0];
break;
case USB_DESCR_TYP_CONFIG:
pDescr = MyCfgDescr;
len = MyCfgDescr[2];
break;
case USB_DESCR_TYP_STRING:
switch( (pSetupReqPak->wValue)&0xff )
{
case 1:
pDescr = MyManuInfo;
len = MyManuInfo[0];
break;
case 2:
pDescr = MyProdInfo;
len = MyProdInfo[0];
break;
case 0:
pDescr = MyLangDescr;
len = MyLangDescr[0];
break;
case 3:
pDescr = (PUINT8)( &MyProductIDInfo[0] );
len = sizeof( MyProductIDInfo );
break;
default:
errflag = 0xFF;
break;
}
break;
default :
errflag = 0xff;
break;
}
if( SetupReqLen>len ) SetupReqLen = len;
len = (SetupReqLen >= DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
memcpy( pEP0_DataBuf, pDescr, len );
//SetupReqLen -= len;
pDescr += len;
}
break;
case USB_SET_ADDRESS:
SetupReqLen = (pSetupReqPak->wValue)&0xff;
break;
case USB_GET_CONFIGURATION:
pEP0_DataBuf[0] = UsbConfig;
if ( SetupReqLen > 1 ) SetupReqLen = 1;
break;
case USB_SET_CONFIGURATION:
UsbConfig = (pSetupReqPak->wValue)&0xff;
break;
case USB_CLEAR_FEATURE:
if( ( pSetupReqPak->bRequestType & 0x1F ) == USB_REQ_RECIP_DEVICE ) /* 清除设备 */
{
if((pSetupReqPak->wValue) == 0x01 )
{
if( MyCfgDescr[ 7 ] & 0x20 )
{
/* 唤醒 */
}
else
{
errflag = 0xFF; /* 操作失败 */
}
}
else
{
errflag = 0xFF; /* 操作失败 */
}
}
else if ( ( pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
{
switch( (pSetupReqPak->wIndex)&0xff )
{
case 0x83:
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~ ( RB_UEP_T_TOG | MASK_UEP_T_RES )) | UEP_T_RES_NAK;
break;
case 0x03:
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~ ( RB_UEP_T_TOG | MASK_UEP_R_RES )) | UEP_R_RES_ACK;
break;
case 0x82:
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
break;
case 0x02:
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
break;
case 0x81:
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
if(CH32CSW)
{
CH32CSW=0;
mCH32UpCsw();
}
break;
case 0x01:
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
if(CH32CSW)
{
CH32CSW = 0;
mCH32UpCsw();
}
break;
default:
errflag = 0xFF;
break;
}
}
else errflag = 0xFF;
break;
case USB_SET_FEATURE: /* Set Feature */
if( ( pSetupReqPak->bRequestType & 0x1F ) == USB_REQ_RECIP_DEVICE ) /* 设置设备 */
{
if(( pSetupReqPak->wValue) == 0x01 )
{
if( MyCfgDescr[ 7 ] & 0x20 )
{
;
}
else
{
errflag = 0xFF; /* 操作失败 */
}
}
else
{
errflag = 0xFF; /* 操作失败 */
}
}
else if( ( pSetupReqPak->bRequestType & 0x1F ) == USB_REQ_RECIP_ENDP ) /* 设置端点 */
{
if(( pSetupReqPak->wValue) == 0x00 )
{
switch(pSetupReqPak->wIndex)
{
case 0x83:
R8_UEP3_CTRL = (R8_UEP3_CTRL & (~RB_UEP_R_TOG)) | UEP_T_RES_STALL;/* 设置端点3 IN STALL */
break;
case 0x03:
R8_UEP3_CTRL = (R8_UEP3_CTRL & (~RB_UEP_R_TOG)) | UEP_R_RES_STALL;/* 设置端点3 OUT Stall */
break;
case 0x82:
R8_UEP2_CTRL = (R8_UEP2_CTRL & (~RB_UEP_R_TOG)) | UEP_T_RES_STALL;/* 设置端点2 IN STALL */
break;
case 0x02:
R8_UEP2_CTRL = (R8_UEP2_CTRL & (~RB_UEP_R_TOG)) | UEP_R_RES_STALL;/* 设置端点2 OUT Stall */
break;
case 0x81:
R8_UEP1_CTRL = (R8_UEP1_CTRL & (~RB_UEP_R_TOG)) | UEP_T_RES_STALL;/* 设置端点1 IN STALL */
break;
case 0x01:
R8_UEP1_CTRL = (R8_UEP1_CTRL & (~RB_UEP_R_TOG)) | UEP_R_RES_STALL;/* 设置端点1 OUT Stall */
break;
default:
errflag = 0xFF; /* 操作失败 */
break;
}
}
else
{
errflag = 0xFF; /* 操作失败 */
}
}
else
{
errflag = 0xFF; /* 操作失败 */
}
break;
case USB_GET_INTERFACE:
pEP0_DataBuf[0] = 0x00;
if ( SetupReqLen > 1 ) SetupReqLen = 1;
break;
case USB_GET_STATUS:
pEP0_DataBuf[0] = 0x00;
pEP0_DataBuf[1] = 0x00;
if ( SetupReqLen > 2 ) SetupReqLen = 2;
break;
default:
errflag = 0xff;
break;
}
}
}
else errflag = 0xff;
if( errflag == 0xff)
{
// SetupReqCode = 0xFF;
R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;
}
else
{
if( chtype & 0x80 )
{
len = (SetupReqLen>DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
SetupReqLen -= len;
}
else len = 0;
R8_UEP0_T_LEN = len;
R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;
}
break;
case UIS_TOKEN_IN:
switch( SetupReqCode )
{
case USB_GET_DESCRIPTOR:
len = SetupReqLen >= DevEP0SIZE ? DevEP0SIZE : SetupReqLen;
memcpy( pEP0_DataBuf, pDescr, len );
SetupReqLen -= len;
pDescr += len;
R8_UEP0_T_LEN = len;
R8_UEP0_CTRL ^= RB_UEP_T_TOG;
break;
case USB_SET_ADDRESS:
R8_USB_DEV_AD = (R8_USB_DEV_AD&RB_UDA_GP_BIT) | SetupReqLen;
R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
default:
R8_UEP0_T_LEN = 0;
R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
break;
}
break;
case UIS_TOKEN_OUT:
R8_UEP0_T_LEN = 0;
R8_UEP0_CTRL ^= RB_UEP_R_TOG; //状态阶段,对IN响应NAK
break;
case UIS_TOKEN_OUT | 1:
if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
{
if(CH32BULKDOWN)
{
mCH32BulkDownData(); //如果上传数据阶段则调用数据上传
}
else
{ //不是数据下传则判断是否
length = R8_USB_RX_LEN;
if(!length)break; //数据包长度为零则跳出
for(len=0;len!=length;len++)
{
MassPara.buf[len]=pEP1_RAM_Addr[len]; //将数据读入到缓冲区
}
mCH32BulkOnly();
if(BcswStatus ==0 )
{
if(!CH32BULKDOWN){
if(CH32BULKUP) CH32bulkUpData(); //调用批量数据上传
else mCH32UpCsw(); //test
}
}
}
}
break;
case UIS_TOKEN_IN | 1:
if(CH32BULKUP)
{
CH32bulkUpData(); //调用数据上传
}
else if(CH32CSW)
{
CH32CSW = 0;
mCH32UpCsw(); //上传CSW
}
else
{
R8_UEP1_T_LEN = 0;
R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
}
break;
case UIS_TOKEN_OUT | 2:
break;
case UIS_TOKEN_IN | 2:
R8_UEP2_T_LEN = 0;
R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
UpPoint2_Busy = 0;
break;
case UIS_TOKEN_OUT | 3:
if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
{
len = R8_USB_RX_LEN;
DevEP3_OUT_Deal( len );
}
break;
case UIS_TOKEN_IN | 3:
R8_UEP3_T_LEN = 0;
R8_UEP3_CTRL = (R8_UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
break;
case UIS_TOKEN_OUT | 4:
if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
{
R8_UEP4_CTRL ^= RB_UEP_R_TOG;
len = R8_USB_RX_LEN;
DevEP4_OUT_Deal( len );
}
break;
case UIS_TOKEN_IN | 4:
R8_UEP4_T_LEN = 0;
R8_UEP4_CTRL ^= RB_UEP_T_TOG;
R8_UEP4_CTRL = (R8_UEP4_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
break;
default:
break;
}
R8_USB_INT_FG = RB_UIF_TRANSFER;
}
else if( intflag & RB_UIF_BUS_RST )
{
R8_USB_DEV_AD = 0;
R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
R8_USB_INT_FG |= RB_UIF_BUS_RST;
}
else if( intflag & RB_UIF_SUSPEND )
{
if ( R8_USB_MIS_ST & RB_UMS_SUSPEND ) {;}
else{;}
R8_USB_INT_FG = RB_UIF_SUSPEND;
}
else
{
R8_USB_INT_FG = intflag;
}
}
/*******************************************************************************
* Function Name : Set_USBConfig
* Description : Set USB clock.
* Input : None
* Return : None
*******************************************************************************/
void USBHD_ClockCmd(UINT32 RCC_USBCLKSource,FunctionalState NewState)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, NewState);
EXTEN->EXTEN_CTR |= EXTEN_USBHD_IO_EN;
RCC_USBCLKConfig(RCC_USBCLKSource); //USBclk=PLLclk/1.5=48Mhz
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHD,NewState);
}
/*******************************************************************************
* Function Name : main
* Description : Main program.
* Input : None
* Return : None
*******************************************************************************/
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
USART_Printf_Init(115200);
printf("USBHD Device Test\r\n");
pEP0_RAM_Addr = EP0_Databuf;
pEP1_RAM_Addr = EP1_Databuf;
pEP2_RAM_Addr = EP2_Databuf;
pEP3_RAM_Addr = EP3_Databuf;
USBHD_ClockCmd(RCC_USBCLKSource_PLLCLK_1Div5,ENABLE);
USB_DeviceInit();
NVIC_EnableIRQ( USBHD_IRQn );
while(1)
{
;
}
}
/*******************************************************************************
* Function Name : DevEP1_OUT_Deal
* Description : Deal device Endpoint 1 OUT.
* Input : l: Data length.
* Return : None
*******************************************************************************/
void DevEP1_OUT_Deal( UINT8 l )
{
;
}
/*******************************************************************************
* Function Name : DevEP2_OUT_Deal
* Description : Deal device Endpoint 2 OUT.
* Input : l: Data length.
* Return : None
*******************************************************************************/
void DevEP2_OUT_Deal( UINT8 l )
{
;
}
/*******************************************************************************
* Function Name : DevEP3_OUT_Deal
* Description : Deal device Endpoint 3 OUT.
* Input : l: Data length.
* Return : None
*******************************************************************************/
void DevEP3_OUT_Deal( UINT8 l )
{
;
}
/*******************************************************************************
* Function Name : DevEP4_OUT_Deal
* Description : Deal device Endpoint 4 OUT.
* Input : l: Data length.
* Return : None
*******************************************************************************/
void DevEP4_OUT_Deal( UINT8 l )
{
;
}
/*******************************************************************************
* Function Name : USB_IRQHandler
* Description : This function handles USB exception.
* Input : None
* Return : None
*******************************************************************************/
void USBHD_IRQHandler (void)
{
USB_DevTransProcess();
}
main.c文件中描述符部分都进行了注释,便于大家理解,其余部分可以参考《圈圈教你玩USB》。关于USB设备传输过程,可结合应用手册关于USB寄存器介绍进行理解学习。
4、下载验证 将编译好的程序下载到开发板并复位,打开串口调试助手,串口打印如下: 用公对公USB线将开发板与电脑连接起来,打开磁盘驱动器可以看到多了一个U盘设备,如图所示: 查看此电脑,可以看到多了一个U盘,如图所示:
|