前面介绍过如何使用 Arduino 环境进行 Ch32V305 的开发,这次带来的是一个 CH32V305 Arduino 实现模拟 Ch372的例子,参考的是 Ch32v307EVT 中的HS Device的代码。根据Exam中的CH32V30x_List.txt描述,这个CH372例子是模拟自定义USB设备(CH372设备),端点1,3下传,2,4上传,端点1下传的数据从端点3上传,不取反,端点2下传的数据从端点4上传,取反。但是,应该是描述存在错误,实际代码不是这样。
首先,改造代码,然后烧写到板子上。使用 USBView 查看,端点1 有一个 OUT 和 IN; 端点3是OUT,端点4是 IN, 端点5是OUT, 端点6是IN.
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x01 -> Direction: OUT - EndpointID: 1
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0200 = 0x200 max bytes
bInterval: 0x00
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x81 -> Direction: IN - EndpointID: 1
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0200 = 0x200 max bytes
bInterval: 0x00
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x03 -> Direction: OUT - EndpointID: 3
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0200 = 0x200 max bytes
bInterval: 0x00
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x84 -> Direction: IN - EndpointID: 4
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0200 = 0x200 max bytes
bInterval: 0x00
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x05 -> Direction: OUT - EndpointID: 5
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0200 = 0x200 max bytes
bInterval: 0x00
===>Endpoint Descriptor<===
bLength: 0x07
bDescriptorType: 0x05
bEndpointAddress: 0x86 -> Direction: IN - EndpointID: 6
bmAttributes: 0x02 -> Bulk Transfer Type
wMaxPacketSize: 0x0200 = 0x200 max bytes
bInterval: 0x00
对应处理的代码在 ch32v30x_usbhs_device.c 文件中。下面对代码进行研读。
代码中Ch32端点1 OUT 收到的数据直接放到端点1 IN中。
/* end-point 1 data out interrupt */
case USBHS_UIS_TOKEN_OUT | DEF_UEP1:
if ( intst & USBHS_UIS_TOG_OK )
{
/* Write In Buffer */
USBHSD->UEP1_RX_CTRL ^= USBHS_UEP_R_TOG_DATA1;
RingBuffer_Comm.PackLen[RingBuffer_Comm.LoadPtr] = USBHSD->RX_LEN;
RingBuffer_Comm.LoadPtr ++;
if(RingBuffer_Comm.LoadPtr == DEF_Ring_Buffer_Max_Blks)
{
RingBuffer_Comm.LoadPtr = 0;
}
USBHSD->UEP1_RX_DMA = (uint32_t)(&Data_Buffer[(RingBuffer_Comm.LoadPtr) * DEF_USBD_HS_PACK_SIZE]);
RingBuffer_Comm.RemainPack ++;
if(RingBuffer_Comm.RemainPack >= DEF_Ring_Buffer_Max_Blks-DEF_RING_BUFFER_REMINE)
{
USBHSD->UEP1_RX_CTRL = ((USBHSD->UEP1_RX_CTRL) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK;
RingBuffer_Comm.StopFlag = 1;
}
}
break;
端点3收到的数据取反后放到端点4上。
/* end-point 3 data out interrupt */
case USBHS_UIS_TOKEN_OUT | DEF_UEP3:
if ( intst & USBHS_UIS_TOG_OK )
{
len = (uint16_t)(USBHSD->RX_LEN);
USBHSD->UEP3_RX_CTRL ^= USBHS_UEP_R_TOG_DATA1;
USBHSD->UEP3_RX_CTRL = ((USBHSD->UEP3_RX_CTRL) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK;
for(i=0; i<len; i++)
{
USBHS_EP4_Tx_Buf[i] = ~USBHS_EP3_Rx_Buf[i];
}
USBHSD->UEP4_TX_LEN = len;
USBHSD->UEP4_TX_CTRL = (USBHSD->UEP4_TX_CTRL & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
}
break;
类似的端点5收到的数据取反,通过端点6上传
/* end-point 5 data out interrupt */
case USBHS_UIS_TOKEN_OUT | DEF_UEP5:
if ( intst & USBHS_UIS_TOG_OK )
{
len = (uint16_t)(USBHSD->RX_LEN);
USBHSD->UEP5_RX_CTRL ^= USBHS_UEP_R_TOG_DATA1;
USBHSD->UEP5_RX_CTRL = ((USBHSD->UEP5_RX_CTRL) & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_NAK;
for(i=0; i<len; i++)
{
USBHS_EP6_Tx_Buf[i] = ~USBHS_EP5_Rx_Buf[i];
}
USBHSD->UEP6_TX_LEN = len;
USBHSD->UEP6_TX_CTRL = (USBHSD->UEP6_TX_CTRL & ~USBHS_UEP_T_RES_MASK) | USBHS_UEP_T_RES_ACK;
}
break;
从代码上可以看出,Exam中的描述是存在一些问题的。
之后,再编写一个VC 代码,进行速度测试:
代码来自 Ch569 的EVT Package, 有部分修改:
// 2003.09.08, 2003.12.28
//****************************************
//** Copyright (C) W.ch 1999-2005 **
//** Web: http://www.winchiphead.com **
//****************************************
//** DLL for USB interface chip CH375 **
//** C, VC5.0 **
//****************************************
//
// USB总线接口芯片CH375的数据块测试程序 V1.0
// 南京沁恒电子有限公司 作者: W.ch 2003.12
// CH375-BLK V1.0
// 运行环境: Windows 98/ME, Windows 2000/XP
// support USB chip: CH372/CH375
//
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <winioctl.h>
#include "CH375DLL.H"
#pragma comment(lib,"CH375DLL")
#define TEST_DATA_LEN 4096
#define TEST_NUM 1000
unsigned char mReadBuf[TEST_DATA_LEN];
unsigned char mWriteBuf[TEST_DATA_LEN];
//程序入口
void main (int argc,char **argv )
{
unsigned long mLength, mTestCount, mErrCnt,mArg,mFirstTick,mLastTick;
long long mTotal=0;
double speed;
USHORT mCount = 0;
printf( "\nCH372/CH375 Bulk Data Test Program V1.1 , Copyright (C) W.ch 2004.12\n" );
printf( "test data correctness \n" );
mArg = TEST_DATA_LEN;
// 需要使用DLL则需要先加载,没有此句则会自动加载
printf( "*** CH375OpenDevice: 0# \n" );
if ( CH375OpenDevice( 0 ) == INVALID_HANDLE_VALUE ) return; /* 使用之前必须打开设备 */
memset(mWriteBuf, 0xFF, sizeof(mWriteBuf));
mErrCnt=0;
printf( "*** CH375ReadData: 1000 times 4M Byte ***\n" );
mTotal = 0.0;
for ( mTestCount=0; mTestCount < TEST_NUM; ++mTestCount ) // 循环测试
{
if(mTestCount == 0)
{
mFirstTick=GetTickCount();
}
mLength = mArg;
if (CH375WriteEndP(0, 1, mWriteBuf, &mLength)) // 写入成功
{
mTotal += mLength;
if (mLength == 0)
{
Sleep(0); //放弃当前线程的时间片,防止CPU出现100%情况
}
}
else
{ // 写操作失败
printf("S1-T%0ld-C%ld CH375WriteEndP return error, length=%d\n", mTestCount, mTestCount, mTotal);
}
mLength = mArg;
if (CH375ReadEndP(0, 1, mReadBuf, &mLength)) // 接收成功
{
mTotal += mLength;
if(mLength == 0 )
{
Sleep(0); //放弃当前线程的时间片,防止CPU出现100%情况
}
}
else
{
printf( "S1-T%0ld-C%ld CH375ReadData return error, length=%d\n", mTestCount, mTestCount, mTotal );
}
}
mLastTick =GetTickCount();
mLastTick = mLastTick - mFirstTick;
speed=1000;
speed=speed*mTotal/mLastTick;
printf( "*** average speed = %7.1f MBytes/Sec, total=%lld bytes\n", speed/1000/1000, mTotal);
CH375CloseDevice( 0 );
printf( "\nExit.\n" );
_getch();
}
完整的源代码和可执行 EXE, 建议有需要的朋友重新编译。
完整的 Arduino 代码: