『7x24小时有问必答』
一、前言
二、开发板CH32V307V-EVT-R3介绍
三、CH182H2介绍
四、性能测试
五、总结建议
六、基于MounRiver_Studio开发(保姆级操作)

一、前言

      本文分享一款100M以太网PHY芯片,CH182H2。并分享基于官方的开发板CH32V307V-EVT-R3来评估下这款芯片的应用,以及性能测试。具体的性能,参数,特点等可以参考数据手册,这里主要描述一些个人觉得比较有意思的点。
      本文会着重描述该芯片的基本应用,包括原理图分析,官方开发板Demo测试,RAW发送,  TCP收发能测试等,如果是初次使用该芯片的朋友,可以参考本文。

二、开发板CH32V307V-EVT-R3介绍

      官方的CH32V307V-EVT-R3开发板,可以用于评估CH182H2芯片。
资料下载地址
https://www.wch.cn/downloads/CH32V307EVT_ZIP.html
开发板的主要接口资源如下:
1.100M网口
2.MCU引出I/O
3.SWDIO调试口
4.CH32V307VCT6
5.USB全速接口
6.USB高速接口(内置PHY
7.电源开关
8.复位按钮
9.下载按钮
      个人觉得比较好的地方是P6RMII接口引出来了,方便逻辑分析仪直接测量RMII接口,用于测试分析,甚至用于学习RMII接口都是不错的。
三、CH182H2介绍
      开发板是用于评估的载体,本文的重点是CH182H2这颗PHY芯片,所以开发板大致了解,熟悉下原理图,知道有哪些接口,如何使用即可。重点来看CH182H2这颗芯片。该芯片IO口支持3.3/2.5/1.8V,适配多种电压的主控,还兼容RTL8102F。看手册描述,有一款CH182D内置唯一MAC地址,体积小巧,QFN封装才3*3mm
可以从以下地址下载该芯片规格书
https://www.wch.cn/downloads/CH182DS1_PDF.html
      这里顺带提一下,WCH的以太网产品还是挺全的。看他们官网介绍,除了以太网PHY,还提供控制器芯片CH390、协议栈芯片CH394/CH395和转接芯片CH9121等。CH390D尺寸3*3mm,算是目前市面上体积最小的百兆以太网MAC PHY芯片了,内置PHY支持IPv4 TCP/UDP和IPv6 TCP/UDP校验和的生成和检查。带全球唯一MAC地址。

3.1  原理图解析

      根据开发板的原理图,重点看下CH182H2的应用部分。
MCU最小系统部分:
PHY部分:
RMII接口部分,引出IO可使用逻辑分析抓信号:
以太网接口部分:
PHY电源和复位部分:
      从以上原理图可以看出PHY的外围电路是很简单的,可以降低BOM成本。
原理图分为以下部分来看:

1.  电源

  VDDIO: IO电源输入,对地接0.1uF电容。支持3.3V2.5V1.8V
  AVDD33: 3.3V主电源输入,对地接0.1uF并联10uF
  AVDDK:  对地接1uF  电容,供内置LDO用。实测应该为1.2V左右,最大1.5V
  DVDDK:  对地接0.1uF电容,供内置LDO解耦用。实测应该为1.2V,最大1.5V

2.  MDIO

CH182系列MDIOMDC均内置上拉电阻,可省外部上拉,简化电路。

3.  复位

RSTB使用阻容复位即可,典型值4.7K0.1uF。低电平有效。

4.  LED

LED引脚的一个功能是配置PHY地址。
LED1 LED0组合决定PA1 PA0 PHY的地址,默认为01LED0内部上拉,LED1内部下拉。
开发板中使用了默认配置,所以无需额外的4.7k的上下拉。
LED引脚本身还作为LED信号控制,用于表示10M还是100M速度,以及是否在通讯活动的状态,取决于寄存器配置LED_SEL不同,LED1LED0的行为不一样,如下,默认LED_SEL0b11
LED0还可以作为PMEB唤醒事件输出,低有效。

5.  MDI

MDI_TX_P/N MDI_RX_P/N接网络变压器的TD+/- RD+/-即可,网络变压器中心抽头0.1uF对地即可,无需接电源。

6.  中断

INTB引脚通过4.7k上拉到VDDIO
需要RMII模式下,作为中断输出,低有效。

7.  晶振

XIXO外接25M晶体,或者输入25M/50M时钟。PHY内部集成了负载电容为12pF的晶体所需的两个振荡电容,所以对于负载电容为12pF的晶体无需外接电容。
如果晶体负载电容大于12pF,则还需根据实际情况外接负载电容(在内部电容基础上再增加)

8.  RMII接口选择

RXDV引脚默认为内部下拉此时配置为MII接口,如果需要配置为RMII接口则RXDV需要外部接4.7k上拉到VDDIO

9.  TXC时钟模式

RMII模式下,RXD0引脚默认为下拉TXC输出50MHz时钟,
如果外部4.7KΩ上拉VDDIO,则TXC输入50MHz时钟。
开发板中无外部上下拉,使用默认状态TXC输出时钟。
7寄存器16也可配置RMIITXC是输出还是输入时钟。

10.  [R]MII接口

RXDV高有效表示有接收数据。同时用于配置RMII接口还是MII接口。
RXD0~3      MAC接收数据
RXC      PHY输出时钟100M25M10M2.5M
TXD0~3 MAC发送数据
TXC    MII PHY输出时钟,RMIIPHY输出或者输入时钟(RXD0决定)
TXEN  发送使能,高有效。
CRS_DV  高有效,载波或者接收数据不为空闲时高。
COL         高有效,检测到碰撞为高
RXER       高有效,检测到错误为高

3.2  寄存器

      0号寄存器的速度和自动协商,双工模式是需要关注的,对于不能通过引脚配置这些参数的型号需要配置该寄存器,对于能通过引脚配置这些参数的型号则可以不配置该寄存器,CH182H2需要配置该寄存器。默认配置是100M,自动协商使能,全双工,所以默认配置即可满足一般使用。
寄存器都是标准的。寄存器31用于页切换,基础寄存器是标准的,扩展寄存器由厂家自定义功能,详细内容需要咨询厂家

3.3  特点

      详细参数,特点等可以参考数据手册,个人觉得以下特点值得特别提出
1.25M晶体(如果负载电容是12pF)无需外部电容,内置了负载电容为12pF的晶体对应的电容。
2.IO可配不同电压,支持3.3V2.5V1.8V
3.P6引出了RMII接口,方便使用逻辑分析仪测试。
4.CH182D还内置唯一MAC地址。
5.内置以太网50Ω阻抗匹配电阻,外部不要再接49.9Ω50Ω电阻,等效于电压驱动。
6.外围器件简单,BOM成本低。

3.4  建议

      开发板中建议CH182H2VDDIO不要直连VCC182而是通过跳线可外部供指定的电压或者使用板载默认的3.3V方便评估VDDIO使用不同电压(最好是板载就可以选择不同电压,作为评估版要能通过配置就能评估所有功能)

性能测试

      这里来基于iperf进行TCP的收发性能测试先来测试RAW发送可以验证PHY的速率,然后再测试TCP的收发性能。 实测结果先睹为快如下,详见后面的测试介绍。
1.Raw TX:93Mbps
2.TCP TX: 80Mbps
3. TCP RX: 70Mbps

<b mpa-font-style="mlgir5i8t7f">4.1 Raw发送速度测试

      基于CH32V307V-EVT-R3\CH32V307EVT\EVT\EXAM\ETH\MAC_RAW这个工程进行测试
注释掉接收处理与打印,只关注发送
void  WCHNET_MainTask(void){          //RecDataPolling();          WCHNET_QueryPhySta();        /* Query external PHY status */           WCHNET_LinkProcessing();     /* process Link stage task */}
发送代码
       static  uint32_t  sndlen =  0;       static  uint32_t  tick1=0;       static  uint32_t  tick2=0;       extern  uint32_t  volatile  LocalTime;       while(1)      {             WCHNET_MainTask();             if(LinkSta)            {                   if(ETH_SUCCESS ==  MACRAW_Tx(ARPPackage,  sizeof(ARPPackage))){                         ///if(++PktCnt % 100 == 0)                         ///      printf("PktCnt:%d\r\n",PktCnt);                         ///Delay_Ms(100);                        sndlen +=  sizeof(ARPPackage);                         if(tick1 ==  0){                              tick1 = LocalTime;                              tick2 = LocalTime;                        }else{                              tick2 = LocalTime;                        }                         if  (tick2 - tick1 >=  5000){                               uint32_t  speed;                              speed=((uint64_t)sndlen/125)/(tick2-tick1);                                 printf("%d Mbps!\r\n", speed);                              tick1 = tick2;                        sndlen =  0;                        }                  }            }      }}
可以看到几乎可以跑满100Mbps

4.2  接收测试

作为servert接收
所以使用TCPServerDemo
      接收数据流如下:
WCHNET_HandleGlobalInt->WCHNET_HandleSockInt->WCHNET_DataLoopback
我们在WCHNET_DataLoopback记录接收指定长度数据后的时间,用于接收速度测试,
实测,接收速度最大可达70Mbps左右。
关键代码如下
extern  uint32_t  volatile  LocalTime;void  WCHNET_DataLoopback(u8 id){      u32 len;      u32 endAddr = SocketInf[id].RecvStartPoint + SocketInf[id].RecvBufLen;           //Receive buffer end address       if  ((SocketInf[id].RecvReadPoint + SocketInf[id].RecvRemLen) > endAddr) {      //Calculate the length of the received data            len = endAddr - SocketInf[id].RecvReadPoint;      }       else  {            len = SocketInf[id].RecvRemLen;      }       static  uint32_t  recvlen =  0;       static  uint32_t  tick1=0;       static  uint32_t  tick2=0;      recvlen += len;       if(tick1 ==  0){            tick1 = LocalTime;            tick2 = LocalTime;      }else{            tick2 = LocalTime;      }              if  (tick2 - tick1 >=  5000){             uint32_t  speed;            speed=((uint64_t)recvlen/125)/(tick2-tick1);               printf("%d Mbps!\r\n", speed);            tick1 = tick2;            recvlen =  0;      }       WCHNET_SocketRecv(id,  NULL, &len);   }

4.3发送测试

作为client发送
所以使用TCPClientDemo
u8  DESIP[4] = {192,  168,  1,  100}; //destination IP address
改为电脑IP
u8  DESIP[4] = {192,  168,  1,  9};  
端口对应
u16desport=1000;   //destination portu16srcport=1000;                                                             //source port
增加变量,检测到链接或者断开时,设置对应标志,标志是链接状态时才发送
     //if (intstat & SINT_STAT_RECV)                                              //receive data      {             WCHNET_DataLoopback(socketid);                                       //Data loopback      }      volatileintconnect_flag=0;         if  (intstat&SINT_STAT_CONNECT)                                          //connect successfully      {            connect_flag=1;         if  (intstat&SINT_STAT_DISCONNECT)                                      //disconnect      {            connect_flag=0;         if  (intstat&SINT_STAT_TIM_OUT)                                          //timeout disconnect      {            connect_flag=0;
接收处理这里不再发送避免干扰,单独添加发送测试函数
void WCHNET_DataLoopback(u8  id){      u8 i;      u32  len;      u32 endAddr=SocketInf[id].RecvStartPoint+SocketInf[id].RecvBufLen;          //Receive buffer end address         if  ((SocketInf[id].RecvReadPoint+SocketInf[id].RecvRemLen) >endAddr) {      //Calculate the length of the received data             len=endAddr-SocketInf[id].RecvReadPoint;      }       else  {             len=SocketInf[id].RecvRemLen;      }      //i = WCHNET_SocketSend(id, (u8 *) SocketInf[id].RecvReadPoint, &len);             //send data      //if  (i == WCHNET_ERR_SUCCESS) {            WCHNET_SocketRecv(id, NULL, &len);                                                          //Clear sent data      //}
初始发送数据
      for (i=0; i<rece_buf_len; i++){[="" span][="" span]="" socketrecvbuf[0]="i&0xff;" }[="" align][align="left]发送处理
extern" uint32_t[="" span]="" volatile[="" localtime;[="" [="" span]static[="" span]="" span]voidsend_test[="" span]([="" span]void[="" span])[="" span]{[="" if[="" span](connect_flag){[="" static[="" sndlen="0;" tick1="0;" tick2="0;" u8="" id="0;" len="RECE_BUF_LEN;" res="WCHNET_SocketSend(id," (u8*)="" socketrecvbuf[id],="" &len);="" (res!="WCHNET_ERR_SUCCESS)" {[="" ="" printf("snd="" err:%d\r\n",res);[="" sndlen+="0;" }else[="" span](tick1="=0){" (tick2-tick1="">=5000){                  uint32_tspeed;                  speed=((uint64_t)sndlen/125)/(tick2-tick1);                     printf("%d Mbps!\r\n", speed);                  tick1=tick2;                 sndlen=0;            }      }}         while(1)      {             /*Ethernet library main task function,              * which needs to be called cyclically*/             WCHNET_MainTask();             /*Query the Ethernet global interrupt,              * if there is an interrupt, call the global interrupt handler*/             if(WCHNET_QueryGlobalInt())            {                   WCHNET_HandleGlobalInt();            }               /* 发送测试 */             send_test();      }
实测如下
      发送速度为80Mbps左右,会有一些抖动,最大可达90Mbps,可以看到效率是非常不错的,支持硬件校验是一个很大的优势。

4.4  速度优化建议

1.提高MCU主频
User\system_ch32v30x.c中改为144M
#define  SYSCLK_FREQ_144MHz_HSE 144000000
2.增加DMA描述符数/缓存区个数
根据应用场景看是大量收还是大量发,调大对应的方向的描述符数
比如发送多的场景可以加大  ETH_TXBUFNB
User\net_config.h
#define  ETH_TXBUFNB 16      /* The number of descriptors sent by the MAC   */#define  ETH_RXBUFNB 2      /* Number of MAC received descriptors   */
3.增加协议栈缓存
User\net_config.h
根据应用场景看是大量收还是大量发,调大对应的方向的缓存大小。
比如发送多的场景可以加大WCHNET_NUM_TCP_SEG
#define  RECE_BUF_LEN (WCHNET_TCP_MSS*2)     /* socket receive buffer size */#define  WCHNET_NUM_PBUF WCHNET_NUM_POOL_BUF     /* Number of PBUF structures */#define  WCHNET_NUM_TCP_SEG (WCHNET_NUM_TCP*8)     /* The number of TCP segments used to send */
4.打开硬件校验
这个是最能明显提升效率的,因为校验计算很占CPU带宽。
User\net_config.h
#define  HARDWARE_CHECKSUM_CONFIG       1        /* Hardware checksum checking and insertion configuration, 1: enable, 0: disable */
5.数据量尽量按最大包长填充,即应用上层协议设计尽量不要使用短包。

总结建议

      总的来说CH182H2的优点是很明显的,正如3.3的介绍,最主要的就是外围电路可以很简单,降低BOM成本,另外也有不同小封装可选,适应于尺寸限制等场景,同时也可以降低成本,所以选择100M以太网PHY芯片的话可以考虑下CH182系列。
      选用CH32V30x等主控,基于MountRiver  Studio开发,也是很方便的,测试跑RAW数据发送几乎能跑满硬件带宽,跑TCP效率也非常不错发送可达80Mbps多。MountRiver  Studio使用起来个人感觉还是非常丝滑方便的界面也美观。
      另外官方Demo提供了协议栈库可以直接使用减少开发工作量,而对于想自己移植第三方协议栈库或者直接面向底层编程的,可以参考下MAC Raw例程,可以基于此在上面移植以太网协议栈。RMII驱动层也是可以直接使用的。
      注意ISP下载开发板BOOT0不要短接(默认是短接的)
      注意使用仿真器需要先切换到RV模式。
六、基于MounRiver_Studio开发(保姆级操作)
      前面介绍了CH182H2这颗芯片和其对应的评估版,并进行了性能测试,对于只是想了解该芯片的可以参考如果进一步想进行应用开发,则可参考本章内容。本章按照保姆级别操作记录介绍基于官方的Demo开发实践。

6.1  安装MounRiver  Studio

从以下地址下载MounRiver  Studio
https://www.mounriver.com/download

6.2  导入工程

下载开发板资料包CH32V307EVT.ZIP,解压
https://www.wch.cn/downloads/CH32V307EVT_ZIP.html
双击CH32V307EVT\EVT\EXAM\ETH\TCPServer\TCPServer.wvproj打开tcpserver的例程。

6.2.1  配置Netlib

      我们这里要使用RMII100M接口所以要修改使用的驱动文件
右键eth_driver_RMII.cInclude/Exclude From Build添加到编译
同样的方法将eth_driver_10M.c排除编译
即编译以下几个文件

6.2.2  配置浮点库

右键点击TCPServer->Properties
配置使能硬件单精度浮点
再配置链接对应的库文件(可省略)
配置完点击Apply
两个a文件只保留一个即可,这里使用float.a
也可以使用上述方法,将这个库排除编译。
delete按键选择remove

6.2.3  确认芯片型号

右键点击TCPServer->Properties,选择对应的MCU型号
配置完点击Apply

6.3编译

菜单栏点击Project->build Project
编译完成

6.3.1编译注意事项

      如果开启了微软电脑管家服务,MRS2检测到该服务可能导致编译变慢会弹窗提示如下。用户可以按弹窗提示,关闭该服务,编译速度就会恢复正常。
按照如下处理
右键点击左下角WIN图标->计算机管理->服务和应用程序->服务
找到Microsoft PC Manager Service,右键点击->属性
启动类型选择禁用,然后点击停止

6.4  配置仿真器

参考WCH-LinkUserManual
https://www.wch.cn/downloads/WCH-LinkUserManual_PDF.html
接入仿真器后设备管理器下外部接口目录下会看到对应的设备。
MounRiver Studio菜单栏Tools->WCH-LinkUtility
获取当前模式
设置为WCH-LinkRV
右键点击TCPServer->Properties
设置仿真器和参数如下,一般默认即可
其中SVD下是指定寄存器描述文件,这样就可以查看各个外设寄存器
然后点击甲壳虫图标进入仿真环境并下载程序
可以查看外设寄存器。
其他仿真操作,不同IDE都大同小异不再赘述。
新版本MounRiver基于VSCODE框架深度定制,明显比之前基于eclipse的更丝滑,轻量,美观。同时兼容了之前版本的操作习惯,方便熟悉MRS1的用户快速上手,另外对于熟悉VSCODE的用户也会觉得很熟悉可以直接上手。

6.5 ISP下载程序

手里没有WCH-LInk可以使用ISP下载
注意开发板上BOOT0默认跳线到了GND要断开。
BOOT0VCCBOOT1GND是进下载模式,
BOOT0通过下载按键按下接VCC
以下地址下载WCHISPTool_Setup.exe
https://www.wch.cn/downloads/WCHISPTool_Setup_exe.html
双击WCHISPTool_Setup.exe安装
选择MCU
为了方便可以先不使能读保护,否则使能了之后下次下载前需要先解除读保护
USBP5按下下载按键,下复位按键
识别到USB设备
选择HEX文件
CH32V307EVT\EVT\EXAM\ETH\TCPServer\obj\TCPServer.hex
点击下载

6.6运行

接上串口线,参数为115200-8-n-1
按键RST重启
串口打印如下
User\main.c中看到
开发板IP
u8 IPAddr[4] = {192, 168, 1, 10}; //IP address
所以将电脑IP设置为192, 168, 1,  9
打开网络调试助手
作为客户端,连接开发板的服务端192.168.1.10,端口1000
u16 srcport = 1000; //source port
客户端发送数据,开发板原样返回
开发板打印
Intstat这个打印在如下位置添加的
void  WCHNET_HandleGlobalInt(void){         u8 intstat;         u16 i;         u8 socketint;   intstat=WCHNET_GetGlobalInt();   //get global interrupt flag          printf("intstat:%x\r\n",intstat);
相关的处理逻辑位于
WCHNET_HandleSockInt
收到数据后原样返回
void  WCHNET_HandleSockInt(u8 socketid, u8 intstat){      u8i;       if  (intstat&SINT_STAT_RECV)         //receive data      {             WCHNET_DataLoopback(socketid);                                          //Data loopback      }
连接时打印信息
       if  (intstat&SINT_STAT_CONNECT)                                             //connect  successfully      {#if KEEPALIVE_ENABLE            WCHNET_SocketSetKeepLive(socketid, ENABLE);#endif            WCHNET_ModifyRecvBuf(socketid, (u32) SocketRecvBuf[socketid],            RECE_BUF_LEN);             for  (i=0; i<wchnet_max_socket_num; i++)="" {[="" span][="" span]="" if[="" span]="" (socket[="" span]="=0xff)" {="" ="" sa[="" span]ve="" connected="" socket[="" id[="" break[="" span];[="" }[="" printf[="" span]("tcp="" connect="" success\r\n"[="" span]);[="" span]("socket="" id:="" [="" span]%d[="" span]\r\n"[="" span],socket[="" span]);[="" align][align="left]
其他逻辑,断开,超时处理
" (intstat&sint_stat_disconnect)="" disconnect[="" for[="" (i="0;" i<wchnet_max_socket_num;="" d[="" span]elete="" disconnected="" disconnect\r\n"[="" (intstat&sint_stat_tim_out)="" timeout="" timeout\r\n"[=""> </wchnet_max_socket_num;></rece_buf_len;></b>

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码