[RISC-V MCU 应用开发] CH32V307以太网MAC层数据包收发速度测试

[复制链接]
 楼主| 我芯永恒 发表于 2025-2-27 13:31 | 显示全部楼层 |阅读模式
测试平台:
CH32V307VCT6+RTL8211FS
PS:沁恒CH32V307VCT6-R2开发板带有千兆PHY(RTL8211FS),本次测试基于该开发板。该开发板原理图以及PCB图可在CH32V 307 EVT中获取到,如下图。
EVT下载链接如下:https://www.wch.cn/downloads/CH32V307EVT_ZIP.html
4114867bfc590eccc6.png

MCU介绍:
CH32V307是一款RISC-V内核的互联型MCU,系统主频最大支持144MHz,FLASH 256KB,RAM 64KB,FLASH、RAM大小可配置修改。支持以太网通信,集成千兆MAC,并内置10M PHY。本次测试主要对MAC层收发速度进行一个测试。

3517567bfc5c014eee.png

PHY介绍:
RTL8211FS是一款具有高集成度的千兆以太网PHY芯片,可用于网卡、路由器、交换机等网络设备。
测试程序:
CH32V307 EVT提供了以太网相关例程,包含了CH32V307 MAC_RAW的例程,如下图。MAC_RAM例程为MAC层接收和发送数据演示例程,本次测试程序基于该例程进行修改,进行接收、发送的速度测试。
3620267bfc53a5e272.png
例程修改:
由于测试是进行MAC层最大收发速度测试,以太网驱动文件选择RGMII.c这个文件,其他文件排除编译,如下图:
7860567bfc63415453.png
例程讲解:
测试例程为MAC层数据包发送和接收演示例程,不涉及以太网协议栈的处理,单纯进行MAC层的收发。关于该例程main函数,如下:
  1. /*********************************************************************
  2. * @fn      main
  3. *
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]   Main program
  5. *
  6. * [url=home.php?mod=space&uid=266161]@return[/url]  none
  7. */
  8. int main(void)
  9. {
  10.     u8 i;
  11.     uint32_t PktCnt = 0;

  12.     SystemCoreClockUpdate();
  13.     Delay_Init();
  14.     USART_Printf_Init(115200);                                  //USART initialize
  15.     printf("MAC RAW Test\r\n");
  16.     printf("SystemClk:%d\r\n", SystemCoreClock);
  17.     printf("ChipID:%08x\r\n", DBGMCU_GetCHIPID());
  18.     WCHNET_GetMacAddr(MACAddr);                                 //get the chip MAC address
  19.     printf("mac addr:");
  20.     for(i = 0; i < 6; i++)
  21.         printf("%x ", MACAddr[i]);
  22.     printf("\n");
  23.     TIM2_Init();
  24.     ETH_Init(MACAddr);
  25.     /* change source MAC address */
  26.     memcpy(&ARPPackage[6], MACAddr, 6);
  27.     memcpy(&ARPPackage[22], MACAddr, 6);

  28.     while(1)
  29.     {
  30.         WCHNET_MainTask();
  31.         if(LinkSta)
  32.         {
  33.             MACRAW_Tx(ARPPackage, sizeof(ARPPackage));
  34.             if(++PktCnt % 100 == 0)
  35.                 printf("PktCnt:%d\r\n",PktCnt);
  36.             Delay_Ms(100);
  37.         }
  38.     }
  39. }
SystemCoreClockUpdate函数、Delay_Init函数、USART_Printf_Init函数主要进行系统时钟、延时函数、串口打印函数的初始化,不做具体介绍。
WCHNET_GetMacAddr函数主要用于获取CH32V307的MAC地址。MAC地址,即发送这个帧的设备希望接收这个帧的设备地址,由IEEE为生产商分配,全球唯一,6字节48 位。 CH32V307的MAC地址出厂时已烧录在芯片内部。地址的发送遵循低有效位在前的原则。
  1. * @fn      WCHNET_GetMacAddr
  2. *
  3. * [url=home.php?mod=space&uid=247401]@brief[/url]   Get the MAC address
  4. *
  5. * [url=home.php?mod=space&uid=266161]@return[/url]  none.
  6. */
  7. void WCHNET_GetMacAddr( uint8_t *p )
  8. {
  9.     uint8_t i;
  10.     uint8_t *macaddr = (uint8_t *)(ROM_CFG_USERADR_ID+5);

  11.     for(i=0;i<6;i++)
  12.     {
  13.         *p = *macaddr;
  14.         p++;
  15.         macaddr--;
  16.     }
  17. }
WCHNET_GetMacAddr函数具体内容如上,MAC地址存放于0x1FFFF7E8+5起始处,读取对应地址可获取CH32V307内部MAC地址。main函数中获取MAC地址之后将其打印出来。
TIM2_Init函数主要用于检测以太网PHY连接的状态。定时器10ms进一次中断。在定时器中断函数中,主要对定时器周期进行加法计数。
9248067bfd557b8568.png
LocalTime主要用于查询PHY状态,1s查询一次,PHY状态查询函数如下:
  1. /*********************************************************************
  2. * @fn      WCHNET_QueryPhySta
  3. *
  4. * @brief   Query external PHY status
  5. *
  6. * @return  none.
  7. */
  8. #if !LINK_STAT_ACQUISITION_METHOD
  9. void WCHNET_QueryPhySta(void)
  10. {
  11.     u16 phy_stat;
  12.     if(QUERY_STAT_FLAG){                                         /* Query the PHY link status every 1s */
  13.         LastQueryPhyTime = LocalTime / 1000;
  14.         ETH_WritePHYRegister( PHY_ADDRESS, 0x1F, 0x0a43 );
  15.         /*In some cases the status is not updated in time,
  16.          * so read this register twice to get the correct status value.*/
  17.         ETH_ReadPHYRegister( PHY_ADDRESS, 0x1A);
  18.         phy_stat = ETH_ReadPHYRegister( PHY_ADDRESS, 0x1A) & 0x04;
  19.         if(phy_stat != LastPhyStat){
  20.             ETH_PHYLink();
  21.         }
  22.     }
  23. }
  24. #endif
WCHNET_QueryPhySta函数为外部PHY连接状态查询函数,函数中,首先对QUERY_STAT_FLAG标志进行判断,QUERY_STAT_FLAG的定义如下: 3302167bff56079268.png
根据QUERY_STAT_FLAG的定义,当LocaTime的值为1000时,其值为1。WCHNET_QueryPhySta函数中if条件成立,执行if判断内的语句。在if语句中,LastQueryPhyTime记录查询次数,然后通过对PHY寄存器的操作查询外部PHY的连接状态;ETH_WritePHYRegister( PHY_ADDRESS, 0x1F, 0x0a43 );完成对PHY寄存器的写入,该操作相当于选择PHY寄存器0xa43这个页面,默认是0xa42,如下图
1011467bff57ddd89b.png

选择对应的PHY寄存器页面之后,可对该页面的寄存器进行读取。
ETH_ReadPHYRegister( PHY_ADDRESS, 0x1A);函数对0x1A寄存器进行读取,0x1A寄存器具体如下:
6023267bff59bb8a04.png
phy_stat = ETH_ReadPHYRegister( PHY_ADDRESS, 0x1A) & 0x04;主要对0x1A寄存器位2的值进行判断,位2表示Link连接状态,当Link连接,该位值为1,执行ETH_PHYLink函数。
ETH_PHYLink函数内容如下:
  1. /*********************************************************************
  2. * @fn      ETH_PHYLink
  3. *
  4. * @brief   Configure MAC parameters after the PHY Link is successful.
  5. *
  6. * @param   none.
  7. *
  8. * @return  none.
  9. */
  10. void ETH_PHYLink( void )
  11. {
  12.     u32 phy_stat;

  13.     ETH_WritePHYRegister( gPHYAddress, 0x1F, 0x0a43 );
  14.     /*In some cases the status is not updated in time,
  15.      * so read this register twice to get the correct status value.*/
  16.     ETH_ReadPHYRegister( gPHYAddress, 0x1A);
  17.     phy_stat = ETH_ReadPHYRegister( gPHYAddress, 0x1A);
  18. #if !LINK_STAT_ACQUISITION_METHOD
  19.     LastPhyStat = phy_stat & 0x04;
  20. #endif
  21.     if( phy_stat & 0x04 )
  22.     {
  23.         printf("Link Suc\r\n");
  24.         if( phy_stat & 0x08 )
  25.         {
  26.             ETH->MACCR |= ETH_Mode_FullDuplex;
  27.         }
  28.         else
  29.         {
  30.             ETH->MACCR &= ~ETH_Mode_FullDuplex;
  31.         }
  32.         if( (phy_stat & 0x30) == 0x00 )
  33.         {
  34.             ETH->MACCR &= ~(ETH_Speed_100M|ETH_Speed_1000M);
  35.         }
  36.         else if( (phy_stat & 0x30) == 0x10 )
  37.         {
  38.             ETH->MACCR &= ~(ETH_Speed_100M|ETH_Speed_1000M);
  39.             ETH->MACCR |= ETH_Speed_100M;
  40.         }
  41.         else if( (phy_stat & 0x30) == 0x20 )
  42.         {
  43.             ETH->MACCR &= ~(ETH_Speed_100M|ETH_Speed_1000M);
  44.             ETH->MACCR |= ETH_Speed_1000M;
  45.         }
  46.         ETH_Start( );
  47.         LinkSta = 1;
  48.     }
  49.     else {
  50.         LinkSta = 0;
  51.     }
  52.     phy_stat = ETH_ReadPHYRegister( gPHYAddress, 0x1D);   /* Clear the Interrupt status */
  53. }

以上判断设置完成后,调用ETH_Start函数开启MAC和DMA的接收传输,ETH_Start函数具体内容如下:
  1. /*********************************************************************
  2. * @fn      ETH_Start
  3. *
  4. * @brief   Enables ENET MAC and DMA reception/transmission.
  5. *
  6. * @return  none
  7. */
  8. void ETH_Start(void)
  9. {
  10.     ETH_MACTransmissionCmd(ENABLE);
  11.     ETH_FlushTransmitFIFO();
  12.     ETH_MACReceptionCmd(ENABLE);
  13.     ETH_DMATransmissionCmd(ENABLE);
  14.     ETH_DMAReceptionCmd(ENABLE);
  15. }
ETH_MACTransmissionCmd(ENABLE);函数使能开启MAC发送器;
ETH_FlushTransmitFIFO();使能复位DMA发送FIFO;
ETH_MACReceptionCmd(ENABLE);函数使能开启MAC接收器;
ETH_DMATransmissionCmd(ENABLE);使能开启发送控制位,把发送进程置位运行状态;
ETH_DMAReceptionCmd(ENABLE);使能开始接收控制位,开启接收流程,DMA从当前位置取接收描述符或者从标识符表头位置取接收描述符。
ETH_Start函数执行完成后,将LinkSta标志置1,phy_stat = ETH_ReadPHYRegister( gPHYAddress, 0x1D);函数将清除相应状态标志位。
回归到main函数,TIM2初始化完成后,进行以太网初始化,ETH_Init(MACAddr);函数具体内容如下:
  1. /*********************************************************************
  2. * @fn      ETH_Init
  3. *
  4. * @brief   Ethernet initialization.
  5. *
  6. * @return  none
  7. */
  8. void ETH_Init( uint8_t *macAddr )
  9. {
  10.     ChipId = DBGMCU_GetCHIPID();
  11.     ETH_Configuration( macAddr );
  12.     ETH_DMATxDescChainInit(DMATxDscrTab, MACTxBuf, ETH_TXBUFNB);
  13.     ETH_DMARxDescChainInit(DMARxDscrTab, MACRxBuf, ETH_RXBUFNB);
  14.     pDMARxSet = DMARxDscrTab;
  15.     pDMATxSet = DMATxDscrTab;
  16.     NVIC_EnableIRQ(ETH_IRQn);
  17.     NVIC_SetPriority(ETH_IRQn, 0);
  18. }
ChipId = DBGMCU_GetCHIPID();该语句主要用于获取新片ID;
ETH_Configuration( macAddr );函数主要对以太网进行配置,该函数内容如下:
  1. /*********************************************************************
  2. * @fn      ETH_Configuration
  3. *
  4. * @brief   Ethernet configure.
  5. *
  6. * @return  none
  7. */
  8. void ETH_Configuration( uint8_t *macAddr )
  9. {
  10.     ETH_InitTypeDef ETH_InitStructure;
  11.     uint16_t timeout = 10000;

  12.     /* Enable Ethernet MAC clock */
  13.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ETH_MAC | \
  14.                           RCC_AHBPeriph_ETH_MAC_Tx | \
  15.                           RCC_AHBPeriph_ETH_MAC_Rx, ENABLE);

  16.     gPHYAddress = PHY_ADDRESS;

  17.     /* Enable 1G MAC*/
  18.     EXTEN->EXTEN_CTR |= EXTEN_ETH_RGMII_SEL;
  19.     RCC_ETH1GCLKConfig(RCC_ETH1GCLKSource_PB1_IN);
  20.     RCC_ETH1G_125Mcmd(ENABLE);
  21.     /* Enable RGMII GPIO */
  22.     ETH_RGMIIPinInit();

  23.     /* Reset ETHERNET on AHB Bus */
  24.     ETH_DeInit();

  25.     /* Software reset */
  26.     ETH_SoftwareReset();

  27.     /* Wait for software reset */
  28.     do{
  29.         Delay_Us(10);
  30.         if( !--timeout )  break;
  31.     }while(ETH->DMABMR & ETH_DMABMR_SR);

  32.     /* ETHERNET Configuration */
  33.     /* Call ETH_StructInit if you don't like to configure all ETH_InitStructure parameter */
  34.     ETH_StructInit(Ð_InitStructure);
  35.     /* Fill ETH_InitStructure parameters */
  36.     /*------------------------   MAC   -----------------------------------*/
  37.     ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;                                      //全双工模式
  38.     ETH_InitStructure.ETH_Speed = ETH_Speed_1000M;                                         //1000M模式
  39.     ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;                    //使能开启自动协商
  40.     ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;                         //关闭自动循环模式
  41.     ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
  42.     ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;         //填充&CRC 自动剥离使能位,配置MAC不改变帧的内容
  43.     /* Filter function configuration */
  44.     ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;                             //MAC只把通过了过滤器的帧转发到接收队列中
  45.     ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;                   //关闭混杂模式
  46.     ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;  //接收所有广播帧
  47.     ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;       //多播过滤,完美地址过滤
  48.     ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;           //单播过滤,完美地址过滤
  49.     /*------------------------   DMA   -----------------------------------*/
  50.     /* When we use the Checksum offload feature, we need to enable the Store and Forward mode:
  51.     the store and forward guarantee that a whole frame is stored in the FIFO, so the MAC can insert/verify the checksum,
  52.     if the checksum is OK the DMA can handle the frame otherwise the frame is dropped */
  53.     ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable;
  54.     ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;
  55.     ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;
  56.     ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Enable;                        //转发错误帧控制位,接收FIFO会丢弃有错误的帧
  57.     ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Enable;      //转发过短帧控制位,接收FIFO转发长度过短的帧
  58.     ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Disable;
  59.     /* Configure Ethernet */
  60.     ETH_RegInit( Ð_InitStructure, gPHYAddress );

  61.     /* Configure MAC address */
  62.     ETH->MACA0HR = (uint32_t)((macAddr[5]<<8) | macAddr[4]);
  63.     ETH->MACA0LR = (uint32_t)(macAddr[0] | (macAddr[1]<<8) | (macAddr[2]<<16) | (macAddr[3]<<24));

  64.     /* Mask the interrupt that Tx good frame count counter reaches half the maximum value */
  65.     ETH->MMCTIMR = ETH_MMCTIMR_TGFM;
  66.     /* Mask the interrupt that Rx good unicast frames counter reaches half the maximum value */
  67.     /* Mask the interrupt that Rx crc error counter reaches half the maximum value */
  68.     ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFCEM;

  69.     ETH_DMAITConfig(ETH_DMA_IT_NIS |\
  70.                 ETH_DMA_IT_R |\
  71.                 ETH_DMA_IT_T |\
  72.                 ETH_DMA_IT_AIS |\
  73.                 ETH_DMA_IT_RBU,\
  74.                 ENABLE);

  75.     /* Configure the polarity and delay of TXC */
  76.     RGMII_TXC_Delay(0, 4);
  77. #if LINK_STAT_ACQUISITION_METHOD
  78.     /* Configure the PHY interrupt function, the supported chip is: RTL8211FS */
  79.     PHY_InterruptInit( );
  80.     /* Configure EXTI Line7. */
  81.     EXTI_Line_Init( );
  82. #endif
  83. }
(未完待续)


低语之树 发表于 2025-7-15 15:49 | 显示全部楼层
确实没搞完呢,看看你是怎么做丢包测试的
AquaWhisper 发表于 2025-7-19 15:36 | 显示全部楼层
速度测试?这不是ping一下就知道了吗,一般都是测试丢不丢包
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

78

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部