打印
[RISC-V MCU 应用开发]

第八十四章、CH32V103应用教程——USB模拟U盘

[复制链接]
4894|32
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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盘,如图所示:

83、CH32V103 USB模拟U盘.rar

491.21 KB

使用特权

评论回复

相关帖子

沙发
jheng| | 2022-4-28 15:10 | 只看该作者
请问下大佬,这个程序为什么不能进行存储

使用特权

评论回复
板凳
薅羊电子网| | 2022-4-29 10:00 | 只看该作者
大神,可以出个更详细的教程。学习学习

使用特权

评论回复
地板
sadicy| | 2022-5-12 20:55 | 只看该作者
这一大串~~~

使用特权

评论回复
5
koala889| | 2022-5-27 20:36 | 只看该作者
下载试试,学习下

使用特权

评论回复
6
abotomson| | 2022-6-2 09:34 | 只看该作者
这个需要驱动吗?      

使用特权

评论回复
7
modesty3jonah| | 2022-6-2 09:43 | 只看该作者
USB模拟的速度能够到多少?     

使用特权

评论回复
8
jstgotodo| | 2022-6-2 14:56 | 只看该作者
最大支持多少内存的U盘呢?

使用特权

评论回复
9
ingramward| | 2022-7-9 13:28 | 只看该作者
这个读取速度怎么样  

使用特权

评论回复
10
DIY小幸福| | 2022-8-12 20:25 | 只看该作者
掉电后,数据会丢失。新建文本文档,写入数据后重新打开也会丢失

使用特权

评论回复
11
1988020566| | 2022-8-20 13:24 | 只看该作者
可以参考cherryusb吗   

使用特权

评论回复
12
jtracy3| | 2022-8-20 13:33 | 只看该作者
这个可以,使用什么通信协议呢  

使用特权

评论回复
13
kissdb| | 2022-10-10 09:34 | 只看该作者
能出个SPI存储器模拟U盘的就更好了

使用特权

评论回复
14
macpherson| | 2022-12-1 19:14 | 只看该作者
这个字符是如何确定的?              

使用特权

评论回复
15
modesty3jonah| | 2022-12-1 19:23 | 只看该作者
NANDFLASH模拟U盘,不错。

使用特权

评论回复
16
robertesth| | 2022-12-1 22:27 | 只看该作者
CH32V103 USB 内部FLASH模拟U盘可以吗?

使用特权

评论回复
17
pentruman| | 2022-12-2 22:58 | 只看该作者
之前用过USB单片机CH559模拟U盘应用实例

使用特权

评论回复
18
sesefadou| | 2022-12-3 14:24 | 只看该作者
CH32V103不是自带这个功能的吗

使用特权

评论回复
19
febgxu| | 2022-12-4 19:51 | 只看该作者
可以实现虚拟串口的功能吗?              

使用特权

评论回复
20
cemaj| | 2022-12-4 21:52 | 只看该作者
USB通fatfs模拟小U盘  

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

132

主题

293

帖子

34

粉丝