RT-thread using W5500 notes-step guide

RT-thread
ORIGINAL POST
By Unknown
components
Hardware Components
W5500
X 1
STM32F407ZG
X 1
Software Apps and online services
STM32CUBEMX
details

Rt-thread.PNG

1 Preparation

  • Hardware preparation: STM32F407ZG, ST-Link, USB to serial port module (there is also an on-board serial communication interface)
  • Software preparation: RT-Thread Studio

2 Process

Simple process of the whole project

        The entire project process is completed on RT-Thread Studio. The graphical configuration of RT-Thread Studio is very convenient for users, provided that the project uses RT-Thread Standard Edition or Smart Edition. Nano version, that will not be able to use the component pack.

3 Create a project

        The method of creating a project is very simple. You only need to select the corresponding chip model when creating a new project. I use the STM32F407ZG chip. By default, there is no STM32F4 series chip package support in RT-Thread Studio, so you need to download it manually. .

3.1 Download STM32F4 series chip package

        Step 1: Click “File” in the upper left corner and select “New” –> “RT-Thread Project”.

        Step 2: Find “Series:” in the new window, click the drop-down box behind and select “Add More”.

        Step 3: Next, find the “STM32F4” option, check it and click Install. There is a high probability that the installation is unsuccessful, because when downloading this resource, authentication is required to prevent malicious access (I guess), so we can only use the manual download method.

        Step 4: Enter the download URL you see below the download window into the browser address bar (you can use the picture-to-text function of QQ screenshots), and follow the steps to download.

        Step 5: Unzip the downloaded resources, change the name of the unzipped folder to “STM32F4”, and then copy the folder to the repoExtractChip_Support_PackagesRealThread directory in the RT-Thread Studio installation directory, such as: D:RT-ThreadStudiorepoExtractChip_Support_PackagesRealThread. (Note: the unzipped folder is the file, not another folder with the same name)

        Step 6: Done, now the chip package of the STM32F4 series should appear when you create a project in RT-Thread Studio.

Screenshot of Step 1 Screenshot of Step 2 Screenshot of Step 3 Screenshot of Step 4 Screenshot of Step 5

3.2 Create a project

        Click “File” in the upper left corner, select “New” –> “RT-Thread Project”, enter the project name and select the corresponding chip and the debugger to be used, and click Finish.

Screenshot of creating project

4 Configure SPI

        Step 1: Double-click to open “RT-Thread Sertting”, find the SPI component, click to open and use the CTRL+Sbutton save.

        Step 2: Double-click to open “CubeMX Settings”, and configure the clock and pin multiplexing functions. Specifically how to configure, you can search by yourself or refer to the “attachment” at the end of the article.

        Step 3: After the configuration is complete, click the “Compile” button to compile to ensure the correctness of the current code (the small hammer in the upper left corner is the compile button, which can only be clicked when the project is selected, otherwise the compiler does not know which project to compile).

Screenshot of Step 1 Screenshot of Step 2 Screenshot of Step 3

5 Configure the W5500 software package

        Step 1: Add the W5500 package using RT-Thread Settings. Click “RT-Thread Studio” –> “Add Package”, search in the new window W5500and click the “Add” button.

        Step 2: After adding, you can see an additional WIZneticon .

        Step 3: Right-click the WIZneticon , select “Configure”, and then click the “WIZnet device configure” drop-down box to configure the properties of the SPI. After the configuration is complete, press the CTRL+Sbutton to save. If you compile at this time, there will be many warnings.

When configuring here, the main configuration is the SPI device name and pin number under the WIZnet device configureoption .

The pin numbers can be viewed in the drivers/drv_gpio.c file.

        Step 4: Mount the SPI device (the SPI configuration done before is only to register the SPI bus with the kernel, and the device needs to be manually mounted, the device here is W5500). Because of WIZnetthe configuration, RT-Thread Studio will generate a packages directory in the project directory. Open the packages/src/wiz.c file, find the int wiz_init(void)function there is a comment in the function “/* I think you can attach w5500 into spi bus at here. You can use this function to realize.*/”, cancel Comment the next line of the comment about the code and follow this function declaration to mount the SPI device.

        Step 5: Add to the top of the packagew/src/wiz.c file #include <board.h>to increase the definition of the GPIO_Typedef type, otherwise the definition of GPIO_Typedef will not be found during compilation. Finally, you can compile the download program to see if the device is successfully mounted.

Screenshot of Step 1 Screenshot of Step 2 Screenshot of Step 3 Screenshot of Step 4 Screenshot of Step 5

6 Testing the W5500

        After downloading, you can test whether the W5500 driver can be used normally through the finish shell. Use the ifconfigcommand to check whether the IP address is obtained (test whether DHCP works), and use the pingcommand to test whether the network can be connected normally.

Test the W5500 driver

The MAC address at this time is the default “00-E0-81-DC-53-1A”. If you want to modify it, you can call the “int wiz_set_mac(const char *mac);” function to modify it.

7 Official use

        Client, HTTP client, client implemented by select, TCP server, UDP server, these have corresponding routines in the official API reference manual, which are better than what I wrote, you can refer to: here .

        The following routines are written based on my own understanding and are only for reference. The official ones shall prevail.

7.1 Implementing a Simple TCP Client

        I simply drew a process for establishing communication between a TCP client and a server. Based on this process, a simple refinement can easily establish TCP communication.

Simple process of TCP client

Waiting for DHCP to obtain an IP address at first is the simplest but also the easiest place to ignore. If the socket is created before the IP address is obtained, the creation will inevitably fail.

  1. Waiting for DHCP to get IP

        The problem of waiting for DHCP to obtain the IP is how to know whether the IP address has been obtained. A simple and efficient method is to read the IP of the network card repeatedly. If the IP can be read, it is considered that the DHCP has been obtained successfully. However, before using this method, we need to obtain the object of the network card device, so that we can read the IP of the network card. The object struct netdev *net_dev = netdev_get_by_name("W5500");to . After obtaining the network card object, you can use it to read every 1s net_dev->ip_addr.addr. If it is not obtained, the value is 0, and if it is read, the value is not 0.

  1. create socket socket

        The way to create a socket is simple, use int socketfd = socket(AF_INET, SOCK_STREAM, 0);to create a socket.

  1. Client binds socket socket

        If the client wants to bind the socket, it first needs to decide which protocol (IPV4/IPV6), which network card (IP address) and which port to use for communication, assign these data to the sockaddr_instructure , and then call bind(socketfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr));this function to bind fixed socket.

  1. Client connects to server

        Similar to the client binding socket, you need to know the specific information of the server you want to connect to, and then you can connect to the server through the connect(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))function .

  1. Client sends data to server

        Sending data int send_size = send(socketfd, msg, strlen(msg), 0);can be , the parameters are: socket descriptor, head pointer of sending string, string length, 0.

  1. Waiting to receive server data

        It is also relatively simple to wait to receive server data. recv_size = recv(socketfd, recv_buffer, 1024, 0);Use to wait for a piece of data from the server in a blocking manner. The parameters are: socket descriptor, array of received data, maximum length of received data, 0.

The specific code is as follows: (If you don’t see it directly, you can see the picture: code )

/*
 * Date           Author            Notes
 * 2022-03-13     徐浚策                  简单的 Socket 使用 Demo
 */
#include <stdio.h>      // 在这个示例中没用到
#include <string.h>     // 提供 strlen() 函数

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>      // 提供 LOG_D() 等函数,没用到

#include <board.h>      // 提供一些设备的定义,没用到
#include <sys/socket.h> // 提供 socket 的标准函数,如:bind()、connect()等
#include <netdb.h>      // 提供了获取 host 的方法,没有到
#include <netdev.h>     // 提供了网卡相关的定义和函数

#define SERVER_HOST "192.168.31.36"         // 服务器 IP 地址
#define SERVER_PORT   15370                 // 服务器使用的端口

int main(void)
{

    struct sockaddr_in client_addr;         // 客户端套接字地址
    struct sockaddr_in server_addr;         // 服务端套接字地址
    struct netdev *net_dev = RT_NULL;        // netdev 网卡设备
    int socketfd = -1;                      // 套接字文件描述符


    /* 通过网卡名称获取 netdev 网卡对象 */
    net_dev = netdev_get_by_name("W5500");
    if (net_dev == RT_NULL){
        rt_kprintf("get network interface device(%s) failed!n", "W5500");
        return -RT_ERROR;
    }rt_kprintf("get network interface device(%s) success!n", "W5500");

    /* 等待 DHCP 获取 IP 地址成功,超时时间 20s。如果没有 IP 地址,Socket 无法创建。 */
    int count = 20;
    while(count-- && !(net_dev->ip_addr.addr)){
        rt_thread_mdelay(1000);
    }
    if(!count){
        rt_kprintf("get ip failed!n");
        return -RT_ERROR;
    }

    /* 创建一个套接字 */
    if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        rt_kprintf("create socket failed!n");
        return -RT_ERROR;
    }rt_kprintf("create socket success!n");

    /* 初始化需要绑定的客户端地址 */
    client_addr.sin_family = AF_INET;                                       // IPV4
    client_addr.sin_port = htons(8080);                                     // 客户端使用的端口
    client_addr.sin_addr.s_addr = net_dev->ip_addr.addr;                    // 获取网卡对象中的 IP 地址,这个地址是由 DHCP 获取的,没有地址时为 0
    rt_memset(&(client_addr.sin_zero), 0, sizeof(client_addr.sin_zero));    // 这个字段只起填充作用,使得 sockaddr_in 与 sockaddr 长度一样

    /* 客户端绑定套接字 */
    if (bind(socketfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)) < 0){
        rt_kprintf("socket bind failed!n");
        closesocket(socketfd);
        return -RT_ERROR;
    }rt_kprintf("socket bind network interface device(%s) success!n", net_dev->name);

    /* 初始化预连接的服务端地址(配置服务端地址) */
    server_addr.sin_family = AF_INET;                                      // IPV4
    server_addr.sin_port = htons(SERVER_PORT);                             // 服务端使用的端口
    server_addr.sin_addr.s_addr = inet_addr(SERVER_HOST);                  // 服务器的 IP 地址
    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));   // 无实际作用,填充长度

    /* 连接到服务端 */
    if (connect(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0){
        rt_kprintf("socket connect failed!n");
        closesocket(socketfd);
        return -RT_ERROR;
    }rt_kprintf("socket connect success!n");


    /* 向服务端发送数据  */
    int send_size = 0;                                         // 发送的数据长度
    static const char *msg = "Hello, i am stm32f407zg.n";     // 准备向服务端发送的数据
    if ((send_size = send(socketfd, msg, strlen(msg), 0)) <= 0) {
        rt_kprintf("send msg failed!n", send_size);
    }rt_kprintf("send msg success, send_size:%d.n", send_size);

    /* 接收服务器发送的数据,阻塞等待服务端数据,如果想要持续通信,使用 while 循环即可 */
    int recv_size = -1;                     // 接收到的数据长度
    char *recv_buffer = rt_calloc(1, 1024);  // 接收数据的缓冲
    if((recv_size = recv(socketfd, recv_buffer, 1024, 0)) < 0){
        rt_kprintf("receive data failed!n");
    }rt_kprintf("receive data success, recv_size:%d.n", recv_size);
    rt_kprintf("the data is:%sn", recv_buffer);

    return RT_EOK;
}

复制代码

7.2 To be updated…  

 

attached

CubeMX Settings configure SPI

Set the RCC clock

enable SPI

Enable USART1

Configure pin function

Configure pin function

Configuring the Clock Tree Feature

Clock tree configuration

generate code

Finish

At this point the SPI has been configured, but not added to the device list (the device has not been registered with the device manager), you can open #define BSP_USING_SPI2a , which will register the SPI bus with the kernel.

If you want to know if it has been registered, you can check it through the list_device command of the finsh shell.

作者:吃菜要紧
链接:https://juejin.cn/post/7074821127830257700
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Rt-thread.PNG

1 Preparation

  • Hardware preparation: STM32F407ZG, ST-Link, USB to serial port module (there is also an on-board serial communication interface)
  • Software preparation: RT-Thread Studio

2 Process

Simple process of the whole project

        The entire project process is completed on RT-Thread Studio. The graphical configuration of RT-Thread Studio is very convenient for users, provided that the project uses RT-Thread Standard Edition or Smart Edition. Nano version, that will not be able to use the component pack.

3 Create a project

        The method of creating a project is very simple. You only need to select the corresponding chip model when creating a new project. I use the STM32F407ZG chip. By default, there is no STM32F4 series chip package support in RT-Thread Studio, so you need to download it manually. .

3.1 Download STM32F4 series chip package

        Step 1: Click “File” in the upper left corner and select “New” –> “RT-Thread Project”.

        Step 2: Find “Series:” in the new window, click the drop-down box behind and select “Add More”.

        Step 3: Next, find the “STM32F4” option, check it and click Install. There is a high probability that the installation is unsuccessful, because when downloading this resource, authentication is required to prevent malicious access (I guess), so we can only use the manual download method.

        Step 4: Enter the download URL you see below the download window into the browser address bar (you can use the picture-to-text function of QQ screenshots), and follow the steps to download.

        Step 5: Unzip the downloaded resources, change the name of the unzipped folder to “STM32F4”, and then copy the folder to the repoExtractChip_Support_PackagesRealThread directory in the RT-Thread Studio installation directory, such as: D:RT-ThreadStudiorepoExtractChip_Support_PackagesRealThread. (Note: the unzipped folder is the file, not another folder with the same name)

        Step 6: Done, now the chip package of the STM32F4 series should appear when you create a project in RT-Thread Studio.

Screenshot of Step 1 Screenshot of Step 2 Screenshot of Step 3 Screenshot of Step 4 Screenshot of Step 5

3.2 Create a project

        Click “File” in the upper left corner, select “New” –> “RT-Thread Project”, enter the project name and select the corresponding chip and the debugger to be used, and click Finish.

Screenshot of creating project

4 Configure SPI

        Step 1: Double-click to open “RT-Thread Sertting”, find the SPI component, click to open and use the CTRL+Sbutton save.

        Step 2: Double-click to open “CubeMX Settings”, and configure the clock and pin multiplexing functions. Specifically how to configure, you can search by yourself or refer to the “attachment” at the end of the article.

        Step 3: After the configuration is complete, click the “Compile” button to compile to ensure the correctness of the current code (the small hammer in the upper left corner is the compile button, which can only be clicked when the project is selected, otherwise the compiler does not know which project to compile).

Screenshot of Step 1 Screenshot of Step 2 Screenshot of Step 3

5 Configure the W5500 software package

        Step 1: Add the W5500 package using RT-Thread Settings. Click “RT-Thread Studio” –> “Add Package”, search in the new window W5500and click the “Add” button.

        Step 2: After adding, you can see an additional WIZneticon .

        Step 3: Right-click the WIZneticon , select “Configure”, and then click the “WIZnet device configure” drop-down box to configure the properties of the SPI. After the configuration is complete, press the CTRL+Sbutton to save. If you compile at this time, there will be many warnings.

When configuring here, the main configuration is the SPI device name and pin number under the WIZnet device configureoption .

The pin numbers can be viewed in the drivers/drv_gpio.c file.

        Step 4: Mount the SPI device (the SPI configuration done before is only to register the SPI bus with the kernel, and the device needs to be manually mounted, the device here is W5500). Because of WIZnetthe configuration, RT-Thread Studio will generate a packages directory in the project directory. Open the packages/src/wiz.c file, find the int wiz_init(void)function there is a comment in the function “/* I think you can attach w5500 into spi bus at here. You can use this function to realize.*/”, cancel Comment the next line of the comment about the code and follow this function declaration to mount the SPI device.

        Step 5: Add to the top of the packagew/src/wiz.c file #include <board.h>to increase the definition of the GPIO_Typedef type, otherwise the definition of GPIO_Typedef will not be found during compilation. Finally, you can compile the download program to see if the device is successfully mounted.

Screenshot of Step 1 Screenshot of Step 2 Screenshot of Step 3 Screenshot of Step 4 Screenshot of Step 5

6 Testing the W5500

        After downloading, you can test whether the W5500 driver can be used normally through the finish shell. Use the ifconfigcommand to check whether the IP address is obtained (test whether DHCP works), and use the pingcommand to test whether the network can be connected normally.

Test the W5500 driver

The MAC address at this time is the default “00-E0-81-DC-53-1A”. If you want to modify it, you can call the “int wiz_set_mac(const char *mac);” function to modify it.

7 Official use

        Client, HTTP client, client implemented by select, TCP server, UDP server, these have corresponding routines in the official API reference manual, which are better than what I wrote, you can refer to: here .

        The following routines are written based on my own understanding and are only for reference. The official ones shall prevail.

7.1 Implementing a Simple TCP Client

        I simply drew a process for establishing communication between a TCP client and a server. Based on this process, a simple refinement can easily establish TCP communication.

Simple process of TCP client

Waiting for DHCP to obtain an IP address at first is the simplest but also the easiest place to ignore. If the socket is created before the IP address is obtained, the creation will inevitably fail.

  1. Waiting for DHCP to get IP

        The problem of waiting for DHCP to obtain the IP is how to know whether the IP address has been obtained. A simple and efficient method is to read the IP of the network card repeatedly. If the IP can be read, it is considered that the DHCP has been obtained successfully. However, before using this method, we need to obtain the object of the network card device, so that we can read the IP of the network card. The object struct netdev *net_dev = netdev_get_by_name("W5500");to . After obtaining the network card object, you can use it to read every 1s net_dev->ip_addr.addr. If it is not obtained, the value is 0, and if it is read, the value is not 0.

  1. create socket socket

        The way to create a socket is simple, use int socketfd = socket(AF_INET, SOCK_STREAM, 0);to create a socket.

  1. Client binds socket socket

        If the client wants to bind the socket, it first needs to decide which protocol (IPV4/IPV6), which network card (IP address) and which port to use for communication, assign these data to the sockaddr_instructure , and then call bind(socketfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr));this function to bind fixed socket.

  1. Client connects to server

        Similar to the client binding socket, you need to know the specific information of the server you want to connect to, and then you can connect to the server through the connect(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))function .

  1. Client sends data to server

        Sending data int send_size = send(socketfd, msg, strlen(msg), 0);can be , the parameters are: socket descriptor, head pointer of sending string, string length, 0.

  1. Waiting to receive server data

        It is also relatively simple to wait to receive server data. recv_size = recv(socketfd, recv_buffer, 1024, 0);Use to wait for a piece of data from the server in a blocking manner. The parameters are: socket descriptor, array of received data, maximum length of received data, 0.

The specific code is as follows: (If you don’t see it directly, you can see the picture: code )

/*
 * Date           Author            Notes
 * 2022-03-13     徐浚策                  简单的 Socket 使用 Demo
 */
#include <stdio.h>      // 在这个示例中没用到
#include <string.h>     // 提供 strlen() 函数

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>      // 提供 LOG_D() 等函数,没用到

#include <board.h>      // 提供一些设备的定义,没用到
#include <sys/socket.h> // 提供 socket 的标准函数,如:bind()、connect()等
#include <netdb.h>      // 提供了获取 host 的方法,没有到
#include <netdev.h>     // 提供了网卡相关的定义和函数

#define SERVER_HOST "192.168.31.36"         // 服务器 IP 地址
#define SERVER_PORT   15370                 // 服务器使用的端口

int main(void)
{

    struct sockaddr_in client_addr;         // 客户端套接字地址
    struct sockaddr_in server_addr;         // 服务端套接字地址
    struct netdev *net_dev = RT_NULL;        // netdev 网卡设备
    int socketfd = -1;                      // 套接字文件描述符


    /* 通过网卡名称获取 netdev 网卡对象 */
    net_dev = netdev_get_by_name("W5500");
    if (net_dev == RT_NULL){
        rt_kprintf("get network interface device(%s) failed!n", "W5500");
        return -RT_ERROR;
    }rt_kprintf("get network interface device(%s) success!n", "W5500");

    /* 等待 DHCP 获取 IP 地址成功,超时时间 20s。如果没有 IP 地址,Socket 无法创建。 */
    int count = 20;
    while(count-- && !(net_dev->ip_addr.addr)){
        rt_thread_mdelay(1000);
    }
    if(!count){
        rt_kprintf("get ip failed!n");
        return -RT_ERROR;
    }

    /* 创建一个套接字 */
    if((socketfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        rt_kprintf("create socket failed!n");
        return -RT_ERROR;
    }rt_kprintf("create socket success!n");

    /* 初始化需要绑定的客户端地址 */
    client_addr.sin_family = AF_INET;                                       // IPV4
    client_addr.sin_port = htons(8080);                                     // 客户端使用的端口
    client_addr.sin_addr.s_addr = net_dev->ip_addr.addr;                    // 获取网卡对象中的 IP 地址,这个地址是由 DHCP 获取的,没有地址时为 0
    rt_memset(&(client_addr.sin_zero), 0, sizeof(client_addr.sin_zero));    // 这个字段只起填充作用,使得 sockaddr_in 与 sockaddr 长度一样

    /* 客户端绑定套接字 */
    if (bind(socketfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)) < 0){
        rt_kprintf("socket bind failed!n");
        closesocket(socketfd);
        return -RT_ERROR;
    }rt_kprintf("socket bind network interface device(%s) success!n", net_dev->name);

    /* 初始化预连接的服务端地址(配置服务端地址) */
    server_addr.sin_family = AF_INET;                                      // IPV4
    server_addr.sin_port = htons(SERVER_PORT);                             // 服务端使用的端口
    server_addr.sin_addr.s_addr = inet_addr(SERVER_HOST);                  // 服务器的 IP 地址
    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));   // 无实际作用,填充长度

    /* 连接到服务端 */
    if (connect(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0){
        rt_kprintf("socket connect failed!n");
        closesocket(socketfd);
        return -RT_ERROR;
    }rt_kprintf("socket connect success!n");


    /* 向服务端发送数据  */
    int send_size = 0;                                         // 发送的数据长度
    static const char *msg = "Hello, i am stm32f407zg.n";     // 准备向服务端发送的数据
    if ((send_size = send(socketfd, msg, strlen(msg), 0)) <= 0) {
        rt_kprintf("send msg failed!n", send_size);
    }rt_kprintf("send msg success, send_size:%d.n", send_size);

    /* 接收服务器发送的数据,阻塞等待服务端数据,如果想要持续通信,使用 while 循环即可 */
    int recv_size = -1;                     // 接收到的数据长度
    char *recv_buffer = rt_calloc(1, 1024);  // 接收数据的缓冲
    if((recv_size = recv(socketfd, recv_buffer, 1024, 0)) < 0){
        rt_kprintf("receive data failed!n");
    }rt_kprintf("receive data success, recv_size:%d.n", recv_size);
    rt_kprintf("the data is:%sn", recv_buffer);

    return RT_EOK;
}

复制代码

7.2 To be updated…  

 

attached

CubeMX Settings configure SPI

Set the RCC clock

enable SPI

Enable USART1

Configure pin function

Configure pin function

Configuring the Clock Tree Feature

Clock tree configuration

generate code

Finish

At this point the SPI has been configured, but not added to the device list (the device has not been registered with the device manager), you can open #define BSP_USING_SPI2a , which will register the SPI bus with the kernel.

If you want to know if it has been registered, you can check it through the list_device command of the finsh shell.

作者:吃菜要紧
链接:https://juejin.cn/post/7074821127830257700
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

COMMENTS

Please Login to comment
  Subscribe  
Notify of
POSTED BY
TAGS
Reusable S/W