zoologist 发表于 2024-5-17 09:24:19

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]
查看完整版本: CH32V305 模拟 Ch372的例子