Tutorial – OpenCH Chitu Development Board Ethernet Module

1. Introduction

Hello everyone, this is VeriMake, today I will introduce you how to use the Chitu Ethernet accessories.
Before we start, let's take a look at the manual of the main control CH32V307VCT6 chip on the Chitu development board.


From the manual, we can see that 307 has 1G and 10M Ethernet inside. It should be noted that 1G does not contain PHY. If you need to use it, you need an external PHY chip to control it through the corresponding interface. CH32V307 has internal PHY,we just connect the pins to the Ethernet port,then it works.

From the data sheet, we can see that if we need to use 1G, we need to connect a Gigabit chip through the RGMII interface. We did not make such an Ethernet design for Chitu as we did not have the RGMII interface pinned out.
Device connection:

The module is connected to the camera interface of Chitu via the soft cable of the FFC, just be careful not to install the cable in the opposite direction. The correct direction is as shown in the figure. The module does not require a separate power supply after connection. Chitu can be connected to a PC, switch or router via a network cable with RJ-45 connector. Then you can access it in the LAN and receive data sent by Chitu, send data or command to Chitu, as well as communicate between Chitu and Chitu via the network cable. In the following we will first describe the communication between PC and Chitu.

2. Sample demonstration

First of all, open the EVT routine provided by WCH under the ETH directory, there are routines related to the port, we first open the TCPClient routine, this routine is to log in to the TCPServer side of the network as a client, establish a TCP connection with the server side and then receive the information sent by the server side, and then send it to the server side via TCP. This routine needs to be modified before it can be used, mainly the two light control ports on the network port need to be changed to PB8 and PB9.
The modifications are as follows.

void Ethernet_LED_Configuration(void)
{
    GPIO_InitTypeDef  GPIO={0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);    //Modified to port B
    GPIO.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;                  //Modified to 8 and 9 ports
    GPIO.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO);
    Ethernet_LED_LINKSET(1);
    Ethernet_LED_DATASET(1);
}
void Ethernet_LED_LINKSET(u8 setbit)
{
     if(setbit){
         GPIO_SetBits(GPIOB, GPIO_Pin_8);       //Set PB8 to 1
     }
     else {
         GPIO_ResetBits(GPIOB, GPIO_Pin_8);     //Set PB8 to 0
    }
}
void Ethernet_LED_DATASET(u8 setbit)
{
     if(setbit){
         GPIO_SetBits(GPIOB, GPIO_Pin_9);       //Set PB9 to 1
     }
     else {
         GPIO_ResetBits(GPIOB, GPIO_Pin_9);     //Set PB9 to 0
    }
}

After the modification we compile to see the experimental phenomenon first and then we will study the code in detail.

After compiling and downloading the code to Chitu, connect Chitu and PC through the network cable (if the laptop does not have a network port, you can switch to the hub of the network port through USB), set the IP address of the PC's network port to 192.168.1.100, mask 255.255.255.0, gateway 192.168.1.1. After the connection is complete we can debug on the PC with the help of NetAssist to test network communication. Open the NetAssist, set the protocol type to TCP Server and the local host address to 192.168.1.100. If there is no such address in the address drop-down menu, you need to check whether the ip4 address setting of the network port connected to the Chitu meets the above requirement, and whether Chitu is connected first and then open the software. If it is the first one, you only need to modify it as required, if it is the second one, you need to close the software and reopen it. The local port is set to 1000. Open the communication, then the NetAssist will receive a connection. As the picture shows. And you can see that the address of the connection is 192.168.1.10. At this time, click Send, you will see the receiving section displaying the information just sent. In addition, you can also see the relevant connection information by connecting to Chitu through the serial port, as follows:


Let's see how it works in detail.

3. Sample Analysis

Open the project, let's see the difference between this project and other projects. In this project, there is a NetLib directory, which stores two files, WCHNET.h and libwchnet.a. This is a network library made by WCH. In WCHNET.h, we can see the amount of related macro definitions and network control functions. The .a file is the static library of these functions, and the source code is not available here. So we only need to know how to use it. Then, let's take a look at the running process of the program in main.c.
In main function:

int main(void)
{
    u8 i;
    Delay_Init();
    USART_Printf_Init(115200);                                              /*Initialize serial printing*/
    printf("TcpClient Test\r\n");
    SET_MCO();                                  //Set the clock
    TIM2_Init();                                //Initialize Timer 2
    WCH_GetMac(MACAddr);                                                     /*Get the chip Mac address*/
    i=WCHNET_LibInit(IPAddr,GWIPAddr,IPMask,MACAddr);                        /*Initialize ethernet library*/
    mStopIfError(i);
    if(i==WCHNET_ERR_SUCCESS) printf("WCHNET_LibInit Success\r\n");
    while(!(WCHNET_GetPHYStatus()&PHY_LINK_SUCCESS))                         /*Wait for a successful PHY connection*/
     {
       Delay_Ms(100);
     }
    WCHNET_CreatTcpSocket();                                                 /*Create Tcp socket*/

    while(1)
    {
      WCHNET_MainTask();                                                     /*Main function of ethernet library that needs to be called recursively*/
      if(WCHNET_QueryGlobalInt())                                            /*Query the ethernet global interrupt, if there is an interrupt, call the global interrupt handler*/
      {
         WCHNET_HandleGlobalInt();
      }
    }
}

We can see from the code that the network of Chitu is initialized first, and if the network has accessed, the TCP connection is started. In the while loop, the Ethernet main task must be called recursively. By querying the global interrupt of the Ethernet, it can be judged whether there is data received and whether it is still in the state of connection to carry out related work. For example, the routine is interrupted by query, and if data is received, the data will be sent back. Then, let's look at the received Ethernet global interrupt function WCHNET_HandleGlobalInt();

void WCHNET_HandleGlobalInt(void)
{
    u8 initstat;
    u16 i;
    u8 socketinit;

    initstat = WCHNET_GetGlobalInt();                                           /*Get global interrupt flag*/
    if(initstat & GINT_STAT_UNREACH)                                            /*Unreachable interrupt*/
    {
       printf("GINT_STAT_UNREACH\r\n");
    }
   if(initstat & GINT_STAT_IP_CONFLI)                                           /*IP conflict interrupt*/
   {
       printf("GINT_STAT_IP_CONFLI\r\n");
   }
   if(initstat & GINT_STAT_PHY_CHANGE)                                          /*PHY state change interrupt*/
   {
       i = WCHNET_GetPHYStatus();                                               /*Get PHY connection status*/
       if(i&PHY_Linked_Status)
       printf("PHY Link Success\r\n");
   }
   if(initstat & GINT_STAT_SOCKET)                                              /*Socket generates interrupt*/
   {
       for(i = 0; i < WCHNET_MAX_SOCKET_NUM; i ++)
       {
           socketinit = WCHNET_GetSocketInt(i);                               /*Get socket interrupt and clear*/
           if(socketinit)WCHNET_HandleSockInt(i,socketinit);                  /*Socket interrupt query   */
       }
   }
}

In the Ethernet global interrupt, you can query such as connection status, unreachable, socket interruption, etc. After receiving the data from the server, a socket interrupt will be generated. Using the WCHNET_HandleSockInt function, different operations can be performed according to the different interrupts of the socket.

void WCHNET_HandleSockInt(u8 sockeid,u8 initstat)
{
    u32 len;

    if(initstat & SINT_STAT_RECV)                                               /*Socket receive interrupt*/
    {
       len = WCHNET_SocketRecvLen(sockeid,NULL);                                /*Get socket buffer data length */
       printf("WCHNET_SocketRecvLen %d \r\n",len);
       WCHNET_SocketRecv(sockeid,MyBuf,&len);                                   /*Get socket buffer data*/
       WCHNET_SocketSend(sockeid,MyBuf,&len);                                   /*Demo return data*/

    }
    if(initstat & SINT_STAT_CONNECT)                                            /*The socket connection is successfully interrupted*/
    {
        printf("TCP Connect Success\r\n");
    }
    if(initstat & SINT_STAT_DISCONNECT)                                         /*The socket connection is disconnected and interrupted*/
    {
        printf("TCP Disconnect\r\n");
    }
    if(initstat & SINT_STAT_TIM_OUT)                                            /*Socket connection timeout interrupted*/
    {
       printf("TCP Timout\r\n");                                                /*Delay 200ms, reconnect*/
       Delay_Ms(200);
       WCHNET_CreatTcpSocket();
    }
}

Here we can see that if the reception is interrupted, the received data will be sent out through WCHNET_SocketSend(socketid,MyBuf,&len). A message is printed if the connection is successful, a message is printed if the connection is broken, and the connection timeout will not only print the message, but also reconnect. The corresponding global interrupt and socket interrupt can be found in WCHNET.h. As shown in the figure:

When creating a connection, we set the ip, port and other information before, which is set at the beginning of main.c,

u8 IPAddr[4] = {192,168,1,10};                                                                   /*IP address*/
u8 GWIPAddr[4] = {192,168,1,1};                                                                  /*Gateway*/
u8 IPMask[4] = {255,255,255,0};                                                                  /*Subnet mask*/
u8 DESIP[4] = {192,168,1,100};                                                                   /*Destination IP address*/

u8 SocketId;                                                                                     /*socket id number*/
u8 SocketRecvBuf[WCHNET_MAX_SOCKET_NUM][RECE_BUF_LEN];                                           /*socket buffer*/
u8 MyBuf[RECE_BUF_LEN];
u16 desport=1000;                                                                                /*destination port number*/
u16 srcport=1000;                                                                                /*source port number*/

If you need to have multiple Chitu connections in the LAN, the last value of each ip needs to be distinguished.

4. Sample extension

Next we make a little modification and try different functions. For example, the received content is displayed on the LCD. If we receive led on, we will turn on LED1, and if we receive led off, we will turn off LED1.

Step 1: Add LCD related libraries to the project. Copy lcd.c lcd.h font.h to the User directory. Add the lcd initialization function to the main function in main.c:

    Delay_Init();
    USART_Printf_Init(115200);                                              /*Initialize serial port printing*/
    printf("TcpClient Test\r\n");
    lcd_init();
    LCD_SetBrightness(60);
    lcd_set_color(WHITE, BLUE);
    lcd_fill(0, 0, 239, 239, WHITE);
    SET_MCO();

Note that LCD_SetBrightness(60), the larger the value the darker the screen, and the maximum is 100. Then we set the background to white and the print characters to blue.
Now add the received data and display it on the lcd:

if(initstat & SINT_STAT_RECV)                                               /*socket receive interrupt*/
    {
       len = WCHNET_SocketRecvLen(sockeid,NULL);                                /*Get socket buffer data length */
       printf("WCHNET_SocketRecvLen %d \r\n",len);
       WCHNET_SocketRecv(sockeid,MyBuf,&len);                                   /*Get socket buffer data*/
       lcd_show_string(3, 10, 16,"                       ");
       lcd_show_string(3, 10, 16, MyBuf);
       WCHNET_SocketSend(sockeid,MyBuf,&len);                                   /*Demo return data*/

    }

After compiling and downloading, resend the data and observe the screen to see the corresponding information.

Step 2:
To add LED control, you need to initialize led_gpio first, and write the function led_gpio();

void led_gpio(){
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);  //Set PE11 as output pin to control LED1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOE, &GPIO_InitStructure);
}

Then initialize this function in the main function, just add led_gpio() below lcd initialization.
Then modify the receiving section and add the led control.

    if(initstat & SINT_STAT_RECV)                                               /*socket receive interrupt*/
    {
       len = WCHNET_SocketRecvLen(sockeid,NULL);                                /*Get socket buffer data length */
       printf("WCHNET_SocketRecvLen %d \r\n",len);
       WCHNET_SocketRecv(sockeid,MyBuf,&len);                                   /*Get socket buffer data*/

       if(strncmp(MyBuf,"led on",6)==0|strncmp(MyBuf,"led off",7)==0 )
       {
           if (strncmp(MyBuf,"led on",6)==0)
           {
               GPIO_ResetBits(GPIOE, GPIO_Pin_11);
           }
           else
           {
               GPIO_SetBits(GPIOE, GPIO_Pin_11);
           }
       }
       else
       {
           lcd_show_string(3, 10, 32,"                       ");
           lcd_show_string(3, 10, 32, MyBuf);
       }
       WCHNET_SocketSend(sockeid,MyBuf,&len);                                   /*Demo return data*/
    }

It should be noted here that MyBuf will not be emptied after each reception, that means the received data is superimposed, so the character comparison function should use strncmp() of the specified length;
After compiling and downloading, we can test it and see the effect.

Expansion introduction

If you need to form a local area network with multiple Chitu, you need to use the following network structure:

The PC in the picture can also use Chitu as a server.

The current routine uses the tool of the NetAssist, but if you need to design your own upper computer program, we recommend using python for development. Python socket development is very simple and can be used to build a TCP Server in a few sentences. With the interface development of Qt, it is very simple to make a network host computer with an interface.

In addition, according to the Ethernet routine in EVT, we can also configure Chitu as a TCP Server or use UDP communication. These contents are very similar to this routine. If you are interested, you can test it according to this routine.

Leave a Reply

Your email address will not be published. Required fields are marked *