CH32V305 模拟 Ch372的例子
前面介绍过如何使用Arduino 环境进行Ch32V305 的开发,这次带来的是一个CH32V305 Arduino 实现模拟Ch372的例子,参考的是Ch32v307EVT 中的HSDevice的代码。根据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 收到的数据直接放到端点1IN中。
/* 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 = 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 = ~USBHS_EP3_Rx_Buf;
}
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 = ~USBHS_EP5_Rx_Buf;
}
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 的EVTPackage, 有部分修改:
// 2003.09.08, 2003.12.28
//****************************************
//**Copyright(C)W.ch1999-2005 **
//**Web:http://www.winchiphead.com**
//****************************************
//**DLL for USB interface chip CH375**
//**C, VC5.0 **
//****************************************
//
// USB总线接口芯片CH375的数据块测试程序 V1.0
// 南京沁恒电子有限公司作者: W.ch 2003.12
// CH375-BLKV1.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;
unsigned char mWriteBuf;
//程序入口
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代码,看着是不是非常简单?
#include "src\\userUsbCh372\\ch32v30x_usbhs_device.h"
void setup() {
Serial.begin(115200);
Serial.println("Start");
/* Initialize system configuration */
SystemCoreClockUpdate( );
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 );
Delay_Init( );
/* Initialize USBHS interface to communicate with the host*/
USBHS_RCC_Init( );
USBHS_Device_Init( ENABLE );
}
uint8_t ret;
void loop() {
/* Determine if enumeration is complete, perform data transfer if completed */
if(USBHS_DevEnumStatus)
{
/* Data Transfer */
if(RingBuffer_Comm.RemainPack)
{
ret = USBHS_Endp_DataUp(DEF_UEP1, &Data_Buffer[(RingBuffer_Comm.DealPtr) * DEF_USBD_HS_PACK_SIZE], RingBuffer_Comm.PackLen, DEF_UEP_DMA_LOAD);
if(ret == 0)
{
NVIC_DisableIRQ(USBHS_IRQn);
RingBuffer_Comm.RemainPack--;
RingBuffer_Comm.DealPtr++;
if(RingBuffer_Comm.DealPtr == DEF_Ring_Buffer_Max_Blks)
{
RingBuffer_Comm.DealPtr = 0;
}
NVIC_EnableIRQ(USBHS_IRQn);
}
}
/* Monitor whether the remaining space is available for further downloads */
if(RingBuffer_Comm.RemainPack < (DEF_Ring_Buffer_Max_Blks - DEF_RING_BUFFER_RESTART))
{
if(RingBuffer_Comm.StopFlag)
{
RingBuffer_Comm.StopFlag = 0;
USBHSD->UEP1_RX_CTRL = (USBHSD->UEP1_RX_CTRL & ~USBHS_UEP_R_RES_MASK) | USBHS_UEP_R_RES_ACK;
}
}
}
}
完整的代码:
这个程序的意义是:如果你想做一个高速传输设备,不想走Windows的内置协议,但是又不想自己完整实现驱动,那么可以使用对应的代码实现自身的设备,然后使用WCH 提供的驱动,自行完成 设备固件和Windows应用程序。
页:
[1]